gpt4 book ai didi

multithreading - 当我在 Clojure 中定义来自多个线程的变量时会发生什么?

转载 作者:行者123 更新时间:2023-12-04 06:52:08 25 4
gpt4 key购买 nike

当我做类似的事情时:

(def x 123)
(future (def x 456))

第二个线程中的 def 最终修改了主线程中的值。我知道这不是惯用的,我应该使用原子或更复杂的东西。然而,除此之外,这与我的预期相反,因为我在不同的地方读到过变量是“动态的”或“线程本地的”。

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

最佳答案

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

I've read in various places that vars are "dynamic" or "thread-local".

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

def always applies to the root binding, even if the var is thread-bound at the point where def is called.

为了证明这一点:

(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

So, what exactly is happening here? Is the second thread making an unsafe assignment, akin to what would happen if you did the equivalent in C?

取决于您对不安全的定义,但对于多线程而言,它肯定是不协调的和非原子的。您可以使用 alter-var-root 以原子方式更改 var,或者使用类似 refatom 的东西来实现可变状态。

If so, does clojure "allow" for the possibility of other unsafe operations like appending to a list from multiple threads and ending up with an inconsistent data structure?

不是它的持久数据结构,它在概念上是写时复制(尽管副本共享公共(public)知识以提高效率)。在使用 Clojure 和其他函数式语言编写多线程代码时,这会带来很多好处。当您附加到(持久性)列表数据结构时,您并没有就地修改结构;您会通过更改取回结构的新“副本”。您如何处理该新值,大概是通过将其放入某个全局“桶”(如 var、ref、atom 等)来确定更改的“安全性”或原子性。

不过,您可以轻松地从多个线程修改 Java 的线程不安全数据结构之一,并最终陷入糟糕的境地。

关于multithreading - 当我在 Clojure 中定义来自多个线程的变量时会发生什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49294979/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com