and*_*ich 42 concurrency multithreading clojure
我已经阅读了很多关于Clojure在并发性方面有多棒的内容,但我读过的教程中没有一个实际上解释了如何创建一个线程.你刚才做(.start(Thread.func)),还是有另外一种我错过的方式?
Bri*_*per 39
Clojure fn是Runnable如此通常以你发布的方式使用它们,是的.
user=> (dotimes [i 10] (.start (Thread. (fn [] (println i)))))
0
1
2
4
5
3
6
7
8
9
nil
Run Code Online (Sandbox Code Playgroud)
另一个选择是使用代理,在这种情况下你会send或者send-off它将使用池中的线程.
user=> (def a (agent 0))
#'user/a
user=> (dotimes [_ 10] (send a inc))
nil
;; ...later...
user=> @a
10
Run Code Online (Sandbox Code Playgroud)
另一种选择是pcalls和pmap.还有future.它们都记录在Clojure API中.
mik*_*era 32
通常,当我想在Clojure中启动一个线程时,我只是使用未来.
除了易于使用之外,这还有一个优点,即您可以避免使用任何混乱的Java互操作来访问底层的Java线程机制.
用法示例:
(future (some-long-running-function))
Run Code Online (Sandbox Code Playgroud)
这将在另一个线程中异步执行该函数.
(def a (future (* 10 10)))
Run Code Online (Sandbox Code Playgroud)
如果您想获得结果,只需取消引用未来,例如:
@a
=> 100
Run Code Online (Sandbox Code Playgroud)
请注意,@ a将阻塞,直到将来的线程完成其工作.
Car*_*icz 14
编程Clojure直到第167页"使用代理进行异步更新"才解决该问题.
在你开始创建线程之前,请注意Clojure将自己多次任务,只有一半机会.我编写的程序对并发性一无所知,发现当条件合适时,它们占用的CPU不止一个.我知道这不是一个非常严格的定义:我还没有深入探讨这个问题.
但是对于那些你确实需要一个明确的单独活动的场合,Clojure的一个答案显然是代理人.
(agent initial-state)
会创造一个.就等待执行的代码块而言,它不像Java Thread.相反,这是一项等待工作的活动.你通过这样做
(send agent update-fn & args)
这样的例子
(def counter (agent 0))
counter是你的代理人的名字和手柄; 代理的状态是数字0.
设置完成后,您可以将工作发送给代理:
(send counter inc)
将告诉它将给定的函数应用于其状态.
您可以稍后通过取消引用将状态拉出代理:
@counter 将为您提供从0开始的数字的当前值.
函数await将允许您执行类似于join代理程序活动的操作,如果它很长:
(await & agents)会等到他们全部完成; 还有另一个版本需要超时.
是的,你在Clojure中启动Java Thread的方式就像你在那里一样.
然而,真正的问题是:你为什么要这样做?Clojure中有很多更好的并发构造比线程.
如果你看看Clojure中的规范并发例子,Rich Hickey的蚁群模拟,你会看到它正好使用了0个线程.java.lang.Thread在整个源代码中唯一的引用是三次调用Thread.sleep,其唯一目的是减慢模拟速度,以便您可以实际查看 UI中发生的情况.
所有逻辑都在Agent中完成:每个ant的一个代理,动画的一个代理和信息素蒸发的一个代理.比赛场地是交易参考.不是线程也不锁定在视线内.
再加上我的两分钱(7 年后):Clojure 函数实现了扩展的IFn 接口Callable以及Runnable. 因此,您可以简单地将它们传递给像Thread.
如果您的项目可能已经使用core.async,我更喜欢使用go宏:
(go func)
Run Code Online (Sandbox Code Playgroud)
这func在超轻量级IOC(控制反转)线程中执行:
go [...] 将把身体变成一个状态机。在达到任何阻塞操作时,状态机将被“停放”并且实际的控制线程将被释放。[...] 当阻塞操作完成时,代码将被恢复 [...]
如果func要执行 I/O 或一些长时间运行的任务,您应该使用thread它也是 core.async 的一部分(查看这篇优秀的博客文章):
(thread func)
Run Code Online (Sandbox Code Playgroud)
无论如何,如果您想坚持 Java 互操作语法,请考虑使用->(thread/arrow) 宏:
(-> (Thread. func) .start)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
24214 次 |
| 最近记录: |