读书人

Clojure STM 札记-中篇

发布时间: 2013-02-28 11:33:09 作者: rapoo

Clojure STM 笔记-中篇


继续上篇继续完成"Software Transactional Memory"的笔记, 本文关注Clojure处理并发的四种引用类型. Clojure中除了引用类型(Reference Type)之外所有的变量都是immutable.本质上"Reference types are mutable references to immutable data". Clojure有四种引用对象:Var Atom Agent Ref.

Vars Root Value全局共享,可以重新定义thread-specific值;常用作constant,不建议修改变量值.可以修改Var变量值的函数有def set! binding 有一种场景修改Var变量值是可以接受的:修改配置变量,比如开启反射调用警告 (set! *warn-on-reflection* true)
Clojure STM 札记-中篇

Atoms 单一值在所有线程共享,原子访问,线程并发读写安全.可以修改Atom值的function有: reset! compare-and-set! swap! 解析Atom使用@Var-name.Clojure STM 札记-中篇 Clojure STM 札记-中篇
user=> (def a (atom 101))#'user/auser=> @a101user=> (reset! a 23)23user=> @a23user=> (swap! a + 1024)1047user=>
Clojure STM 札记-中篇

Agents 单一值所有线程共享,Agent值在另外的线程调用异步方法(Action)修改.Action返回值作为Agent的新值.Agent值解析使用@var-name. 发送到同一个Agent的Action会队列化,同一时刻只有一个Action修改Agent的值.Action排队的函数有send和send-off.由于Action是异步执行,所以这两个send方法调用会立即返回.它们的区别在于线程池的大小:一个是固定大小的,一个是大小可变的.我们调用send的时候还可以把一些附加参数带过去,比如 (send v * 10);await方法挂起当前线程直到指定Agents集上的所有的action都已经执行完成.await-for功能类似,提供超时处理.Actions如果发送到的Agent在事务中,就会等待直到事务执行完毕.这个特征用来在代码中附加一些有副作用的逻辑. Clojure STM 札记-中篇 Clojure STM 札记-中篇
user=> (def v (agent 123))#'user/vuser=> @v123user=> (send v inc)#<Agent@2e21712e: 124>user=> (send v * 10)#<Agent@2e21712e: 1240>user=> (await v)niluser=> (await-for 1024 v)trueuser=> @v1240user=> user=> (source await)(defn await  "Blocks the current thread (indefinitely!) until all actions  dispatched thus far, from this thread or agent, to the agent(s) have  occurred.  Will block on failed agents.  Will never return if  a failed agent is restarted with :clear-actions true."  {:added "1.0"   :static true}  [& agents]  (io! "await in transaction"    (when *agent*      (throw (new Exception "Can't await in agent action")))    (let [latch (new java.util.concurrent.CountDownLatch (count agents))          count-down (fn [agent] (. latch (countDown)) agent)]      (doseq [agent agents]        (send agent count-down))      (. latch (await)))))nil
Clojure STM 札记-中篇

看一下send和send-off实现的差异:

Clojure STM 札记-中篇
send & send-offuser=> (source send)(defn send  "Dispatch an action to an agent. Returns the agent immediately.  Subsequently, in a thread from a thread pool, the state of the agent  will be set to the value of:  (apply action-fn state-of-agent args)"  {:added "1.0"   :static true}  [^clojure.lang.Agent a f & args]  (.dispatch a (binding [*agent* a] (binding-conveyor-fn f)) args false))niluser=> (source send-off)(defn send-off  "Dispatch a potentially blocking action to an agent. Returns the  agent immediately. Subsequently, in a separate thread, the state of  the agent will be set to the value of:  (apply action-fn state-of-agent args)"  {:added "1.0"   :static true}  [^clojure.lang.Agent a f & args]  (.dispatch a (binding [*agent* a] (binding-conveyor-fn f)) args true))niluser=>
Clojure STM 札记-中篇

Refs Refs只可以在STM Transaction内部进行修改.修改Ref值的函数有ref-set alter commute.Ref的值通过@var-name解析.读一个变量的值不需要使用Transaction,但是如果需要获得多个变量一致的快照就要使用transaction了.注意:Refs是唯一一个需要使用STM来协调的变量类型. Clojure STM 札记-中篇

如何选择alter ref-set ? 你为什么要使用ref-set而不是alter?Clojure惯用法往往是这样的:

读书人网 >编程

热点推荐