在Clojure編程中,大多數(shù)數(shù)據(jù)類型是不可變的,因此當涉及并發(fā)編程時,使用這些數(shù)據(jù)類型的代碼在多個處理器上運行時是相當安全的。 但是許多次,需要共享數(shù)據(jù),并且當涉及多個處理器的共享數(shù)據(jù)時,有必要確保在使用多個處理器時保持數(shù)據(jù)的狀態(tài)的完整性。 這被稱為并發(fā)編程,Clojure提供對這種編程的支持。
通過dosync,ref,set,alter等暴露的軟件事務(wù)存儲器系統(tǒng)(STM)支持以同步和協(xié)調(diào)的方式共享線程之間的變化狀態(tài)。 代理系統(tǒng)支持以異步和獨立的方式共享線程之間的變化狀態(tài)。 原子系統(tǒng)支持以同步和獨立的方式共享線程之間的變化狀態(tài)。 而通過def,綁定等暴露的動態(tài)var系統(tǒng)支持隔離線程內(nèi)的變化狀態(tài)。
其他編程語言也遵循并行編程模型。
它們直接引用可以更改的數(shù)據(jù)。
如果需要共享訪問,則對象被鎖定,值被更改,并且進程繼續(xù)下一次訪問該值。
在Clojure中沒有鎖,但是對不可變持久數(shù)據(jù)結(jié)構(gòu)的間接引用。
Clojure中有三種類型的引用。
Vars -更改在線程中隔離。
Refs -更改在線程之間進行同步和協(xié)調(diào)。
Agents -涉及線程之間的異步獨立變化。
在Clojure中有關(guān)并發(fā)編程的以下操作是可能的。
Clojure中的并發(fā)是基于事務(wù)。 引用只能在事務(wù)中更改。 在事務(wù)中應(yīng)用以下規(guī)則。
我們已經(jīng)看到了dosync塊做了什么,讓我們再看看。
在包含表達式和任何嵌套調(diào)用的事務(wù)中運行表達式(在隱式do中)。 如果此線程上沒有運行,則啟動事務(wù)。 任何未捕獲的異常將中止事務(wù)并流出dosync。
以下是 dosync 的基本語法。
(dosync expression)
參數(shù) - 'expression'是將在dosync塊中出現(xiàn)的一組表達式。
返回值 -無。
讓我們看一個例子,其中我們試圖改變一個引用變量的值。
(ns clojure.examples.example (:gen-class)) (defn Example [] (def names (ref [])) (alter names conj "Mark")) (Example)
上述程序運行時出現(xiàn)以下錯誤。
Caused by: java.lang.IllegalStateException: No transaction running at clojure.lang.LockingTransaction.getEx(LockingTransaction.java:208) at clojure.lang.Ref.alter(Ref.java:173) at clojure.core$alter.doInvoke(core.clj:1866) at clojure.lang.RestFn.invoke(RestFn.java:443) at clojure.examples.example$Example.invoke(main.clj:5) at clojure.examples.example$eval8.invoke(main.clj:7) at clojure.lang.Compiler.eval(Compiler.java:5424) ... 12 more
從錯誤中,您可以清楚地看到,您不能在不首先啟動事務(wù)的情況下更改引用類型的值。
為了使上面的代碼工作,我們必須把alter命令放置在dosync塊中,如下面的程序所做。
(ns clojure.examples.example (:gen-class)) (defn Example [] (def names (ref [])) (defn change [newname] (dosync (alter names conj newname))) (change "John") (change "Mark") (println @names)) (Example)
上述程序產(chǎn)生以下輸出。
[John Mark]
讓我們看另一個dosync的例子。
(ns clojure.examples.example (:gen-class)) (defn Example [] (def var1 (ref 10)) (def var2 (ref 20)) (println @var1 @var2) (defn change-value [var1 var2 newvalue] (dosync (alter var1 - newvalue) (alter var2 + newvalue))) (change-value var1 var2 20) (println @var1 @var2)) (Example)
在上面的例子中,我們有兩個值在dosync塊中被改變。 如果事務(wù)成功,則兩個值都將改變,否則整個事務(wù)將失敗。
上述程序產(chǎn)生以下輸出。
10 20 -10 40
更多建議: