瞭解 Groovy 的並發庫如何利用流行的並行存取模型並使其在 Java 平台上可供訪問
在並發性時代,帶有 4、6 和 16 個處理器核心的晶片變得很普遍,而且在不久的將來,我們會看到帶有上百甚至上千個核心的晶片。這種處理能力蘊含著巨大的可能性,但對於軟體開發人員來說,它也帶來了挑戰。最大限度地利用這些閃耀新核的需求推動了對並發性、狀態管理和為兩者構建的程式設計語言的關注熱潮。
Groovy、Scala 和 Clojure 等 JVM 語言滿足了這些需求。這三種都是較新的語言,運行於高度最佳化的 JVM 之上,可以使用 Java 1.5 中新增的強大的 Java 並發庫。儘管每種語言基於其原理採用不同的方法,不過它們都積極支援並發編程。
在本文中,我們將使用 GPars,一種基於 Groovy 的並發庫,來檢查模型以便解決並發性問題,比如幕後處理、平行處理、狀態管理和線程協調。
為何選擇 Groovy ?為何選擇 GPars ?
Groovy 是運行於 JVM 之上的一種動態語言。基於 Java 語言,Groovy 移除了 Java 代碼中的大量正式文法,並添加了來自其他程式設計語言的有用特性。Groovy 的強大特性之一是它允許編程人員輕鬆建立基於 Groovy 的 DSL。
GPars 或 Groovy Parallel Systems 是一種 Groovy 並發庫,捕捉並發性和協調模型作為 DSL。GPars 的構思源自其他語言的一些最受歡迎的並發性和協調模型,包括:
來自 Java 語言的 executors 和 fork/join
來自 Erlang 和 Scala 的 actors
來自 Clojure 的 agents
來自 Oz 的資料流變數
Groovy 和 GPars 的結合成為展示各種並發性方法的理想之選。甚至不熟悉 Groovy 的 Java 開發人員也能輕鬆關注相關討論,因為 Groovy 的文法以 Java 語言為基礎。本文中的樣本基於 Groovy 1.7 和 GPars 0.10。
後台和平行處理
一個常見的效能難題是需要等待 I/O。I/O 可能涉及到從一個磁碟、一個 web 服務或甚至是一名使用者讀取資料。當一個線程在等待 I/O 的過程中被阻止時,將等待中的線程與原始執行線程分離開來將會很有用,這將使它能繼續工作。由於這種等待是在後台發生的,所以我們稱這種技術為 幕後處理。
例如,假設我們需要這樣一個程式,即調用 Twitter API 來找到針對若干 JVM 語言的最新 tweets 並將它們列印出來。Groovy 能夠使用 Java 庫 twitter4j 很容易就編寫出這樣的程式,如清單 1 所示:
清單 1. 串列讀取 tweets (langTweets.groovy)
import twitter4j.Twitter
import twitter4j.Query
@Grab(group='net.homeip.yusuke', module='twitter4j', version='2.0.10')
def recentTweets(api, queryStr) {
query = new Query(queryStr)
query.rpp = 5 // tweets to return
query.lang = "en" // language
tweets = api.search(query).tweets
threadName = Thread.currentThread().name
tweets.collect {
"[${threadName}-${queryStr}] @${it.fromUser}: ${it.text}"
}
}
def api = new Twitter()
['#erlang','#scala','#clojure'].each {
tweets = recentTweets(api, it)
tweets.each {
println "${it}"
}
}