use*_*135 2 multithreading clojure
当我做的事情:
(def x 123)
(future (def x 456))
Run Code Online (Sandbox Code Playgroud)
所述def在所述第二线程结束修改在主线程的值.我知道这不是惯用的,我应该使用原子或更复杂的东西.然而,除此之外,这与我的期望相反,因为我在各个地方读过变量是"动态的"或"线程本地的".
那么,到底发生了什么?第二个线程是否进行了不安全的分配,类似于在C中执行等效操作时会发生什么?如果是这样,clojure是否"允许"其他不安全操作的可能性,例如从多个线程追加到列表并最终导致数据结构不一致?
首先,def是Clojure中的一种特殊形式,值得一读.
我在不同的地方读过变量是"动态的"或"线程局部的".
他们可以,但这不是典型的用法.从指南:
def始终适用于根绑定,即使var在调用def的点处是线程绑定的.
为了证明这一点:
(def ^:dynamic foo 1)
(binding [foo 2] ;; thread-local binding for foo
(prn foo) ;; "2"
(def foo 3) ;; re-defs global foo var
(prn foo)) ;; "2" (still thread-local binding value)
(prn foo) ;; "3" (now refers to replaced global var)
Run Code Online (Sandbox Code Playgroud)
并有多个线程:
(def ^:dynamic foo 1)
(future
(Thread/sleep 500)
(prn "from other thread" foo))
(binding [foo 2]
(prn "bound, pre-def" foo)
(def foo 3)
(Thread/sleep 1000)
(prn "bound, post-def" foo))
(prn "finally" foo)
;; "bound, pre-def" 2
;; "from other thread" 3
;; "bound, post-def" 2
;; "finally" 3
Run Code Online (Sandbox Code Playgroud)
那么,到底发生了什么?第二个线程是否进行了不安全的分配,类似于在C中执行等效操作时会发生什么?
取决于你对不安全的定义,但就多线程而言,它肯定是不协调的和非原子的.您可以使用alter-var-root原子更改var,或使用类似于ref或atom可变状态的内容.
如果是这样,clojure是否"允许"其他不安全操作的可能性,例如从多个线程追加到列表并最终导致数据结构不一致?
不是它的持久性数据结构,它在概念上是写时复制的(尽管这些副本在效率上有共同的知识).在Clojure和其他函数语言中编写多线程代码时,这会带来很多好处.当您附加到(持久性)列表数据结构时,您不会就地修改结构; 你随着你的改变得到了一个新的结构"副本".你如何处理这个新值,大概是把它放在像var,ref,atom等一些全局"桶"中,决定了变化的"安全性"或原子性.
但是,您可以轻松地从多个线程修改Java的一个线程不安全的数据结构,并最终处于不利的位置.