在Clojure中是否有可能使用代理导致死锁(或其他不良情况)?

hse*_*pin 3 concurrency deadlock clojure agent race-condition

Clojure代理是一个强大的工具.由于使用函数"send"和"send-off"异步发送对代理的操作,理论上不会发生类似死锁的事情.

是否可以使用代理来编写一些Clojure代码(例如从一些操作调用另一个代理到另一个代理),其中我们有一些并发问题 - 它可能是死锁,竞争条件或其他任何东西.

Ale*_*ler 9

sendsend-off添加功能,队列代理并立即返回.因此,由于它们的异步性质,它们不可能死锁.

但是,所使用的工作池用于send计算工作,因此是固定池大小(2 +核心数).如果您(错误地)send使用可以阻止I/O或其他任务的任务调用,该任务将阻止池中固定数量的cpu线程之一.如果您同时使用(2 +#个内核)任务,则可以有效地阻止cpu线程池.解决方案当然是使用正确的send-off代替.使用的工作池send-off是无限制的.

在动作中发送时,代理页面指​​出:

如果在函数执行期间(直接或间接)进行任何其他调度,则它们将一直保持到代理状态发生更改之后.

当调度发生在代理的末尾时,发送将项放在发送队列中并立即返回.因为代理从不阻止等待资源,所以无法创建死锁循环.

数据竞争也不可能- 代理的状态应该是不可变的Clojure数据.代理在发送中应用更改功能,并以原子方式替换代理的状态.读者(通过dereference@)在代理生命周期的某个时刻看到一个稳定的值.如果您需要读者和作者的协调,您必须使用refs.

存在竞争条件的可能性:send来自不同线程的两个调用可以"竞争"放入代理的队列中,并且并发读取器可以根据何时读取代理的时间线来感知不同的(稳定)值.但是,这是异步计算的本质.如果在读取或写入多个资源时需要协调计算,则必须使用refs.