Clojure 中是否有可能使用代理导致死锁(或其他不良情况)?
Clojure 代理是一个强大的工具。由于对代理的操作是使用函数“send”和“send-off”异步发送的,因此理论上不会发生死锁之类的情况。
是否可以使用存在并发问题的代理编写一些 Clojure 代码(例如,从某个操作调用另一个操作到另一个代理)——这可能是死锁、竞争条件或其他任何问题。
Clojure agents are a powerful tool. Since actions to the agents are asynchronously sent using functions "send" and "send-off", in theory something like deadlock couldn't happen.
Is it possible to write some Clojure code (for example invoking from some action another action to another agent) using agents in which we have some concurrency problem - it could be deadlock, race condition or anything else.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
send
和send-off
将函数添加到代理队列中并立即返回。因此,由于它们的异步特性,它们不可能出现死锁。但是,
send
使用的工作池用于计算工作,因此是固定池大小(2 + 核心数)。如果您(错误地)使用可能因 I/O 或其他原因而阻塞的任务调用send
,则该任务将阻塞池中固定数量的 cpu 线程之一。如果您同时执行(2 + 核心数)个任务,则可以有效地阻塞 cpu 线程池。解决方案当然是使用正确的send-off
。send-off
使用的工作池是无限制的。在操作中发送时,代理页面指出:
当调度发生在代理末尾时,发送会将项目放入发送队列中并立即返回。由于代理永远不会阻塞等待资源,因此无法创建死锁循环。
也不可能发生数据竞争 - 代理的状态应该是不可变的 Clojure 数据。代理在发送中应用更改函数并原子地替换代理的状态。读者(通过
取消引用
或@
)在代理生命周期的某个时刻看到稳定的值。如果您需要协调读者和作者,则必须使用 refs。存在竞争条件的可能性:来自不同线程的两次对
send
的调用可以“竞争”被放入代理的队列中,并且并发读取器可能会感知到不同的情况。 (稳定)值取决于他们何时读取代理的时间线。然而,这就是异步计算的本质。如果您希望在读取或写入多个资源时协调计算,则必须使用 refs。send
andsend-off
add the functions to queues for the agent and return immediately. Thus, due to their asynchronous nature, it is not possible for them to deadlock.However, the worker pool used by
send
is intended for computational work and is thus a fixed pool size (2 + # of cores). If you (incorrectly) invokesend
with a task that can block for I/O or something else, that task will block one of the fixed number of cpu threads in the pool. If you did that with (2 + # of cores) tasks at the same time, you could effectively block the cpu thread pool. The solution of course is to use the correctsend-off
instead. The worker pool used bysend-off
is unbounded.On sending within an action, the agents page states:
When the dispatch occurs at the end of the agent, the send places the item in the send queue and returns immediately. Because agents never block waiting for a resource, there is no way to create a deadlock cycle.
There is also no possibility for a data race - the state of an agent should be immutable Clojure data. The agent applies the change function within a send and replaces the state of the agent atomically. Readers (via
dereference
or@
) see a stable value at some point in the agent's lifetime. If you need coordination of readers and writers, you must use refs.There is a possibility of a race condition: two calls to
send
from different threads can "race" to be put in the queue of an agent and also concurrent readers may perceive different (stable) values depending on when they read the agent's timeline. However, this is the nature of asynchronous computation. If you want coordinated computation when reading or writing multiple resources, you must use refs.我不确定这是否可能,因为“发送”调用的异步性质可以防止此类死锁问题。如果发送是同步的,那么很容易就可以在发送函数中再次调用发送给同一个代理,现在如果是同步的,发送就会卡住。
I am not sure if that would be possible because the Asynchronous nature of the "send" calls are there to prevent such kind of deadlock issues. In case send was synchronous then it would have been easily possible i.e to call send again in the send function to the same agent, now send would get stuck if it was synchronous.