Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 在Clojure中从多个线程定义变量时会发生什么?_Multithreading_Clojure - Fatal编程技术网

Multithreading 在Clojure中从多个线程定义变量时会发生什么?

Multithreading 在Clojure中从多个线程定义变量时会发生什么?,multithreading,clojure,Multithreading,Clojure,当我做以下事情时: (def x 123) (future (def x 456)) 第二个线程中的def最终修改了主线程中的值。我明白这不是惯用语,我应该使用原子或更复杂的东西。然而,撇开这一点不谈,这与我的预期相反,因为我在不同的地方读到vars是“动态的”或“线程本地的” 那么,这里到底发生了什么?第二个线程是否正在进行不安全的赋值,类似于在C中执行等效赋值时会发生什么情况?如果是这样,clojure是否“允许”其他不安全操作的可能性,例如从多个线程附加到列表,并以不一致的数据结构结束?

当我做以下事情时:

(def x 123)
(future (def x 456))
第二个线程中的
def
最终修改了主线程中的值。我明白这不是惯用语,我应该使用原子或更复杂的东西。然而,撇开这一点不谈,这与我的预期相反,因为我在不同的地方读到vars是“动态的”或“线程本地的”


那么,这里到底发生了什么?第二个线程是否正在进行不安全的赋值,类似于在C中执行等效赋值时会发生什么情况?如果是这样,clojure是否“允许”其他不安全操作的可能性,例如从多个线程附加到列表,并以不一致的数据结构结束?

可以使用
alter var root
对vars的根绑定进行线程安全修改:

(do (future (Thread/sleep 10000) (alter-var-root #'v inc)) (def v 2))
使用相同的名称多次调用
def
只会覆盖最后一次调用获胜的根绑定

然而,在习惯用法Clojure中,def只能在顶层使用(除了宏之类的例外)。

首先,是Clojure中的一种特殊形式,值得一读

我在不同的地方读到vars是“动态”或“线程本地”的

它们可以是,但这不是典型的用法。从指南中:

def
始终应用于根绑定,即使变量在调用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)
并且具有多个线程:

(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
那么,这里到底发生了什么?第二个线程是否正在进行不安全的赋值,类似于在C中执行等效赋值时会发生什么情况

这取决于您对不安全的定义,但对于多个线程来说,它肯定是不协调的和非原子的。您可以使用
altervar root
以原子方式更改var,或者使用
ref
atom
之类的方法来更改可变状态

如果是这样,clojure是否“允许”其他不安全操作的可能性,例如从多个线程附加到列表,并以不一致的数据结构结束

而不是它的持久数据结构,它们在概念上是写时拷贝的(尽管拷贝为了效率而共享公共知识)。在使用Clojure和其他函数式语言编写多线程代码时,这会带来很多好处。当您附加到(持久的)列表数据结构时,您并没有就地修改该结构;您可以通过更改获得结构的新“副本”。你如何处理这个新值,大概是通过把它放在一个全局的“桶”里,比如var、ref、atom等等,决定了改变的“安全性”或原子性

然而,您可以很容易地从多个线程中修改Java的一个线程不安全数据结构,并最终陷入一个糟糕的境地