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

发布于 2024-12-18 06:37:42 字数 162 浏览 6 评论 0原文

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

冷夜 2024-12-25 06:37:42

sendsend-off 将函数添加到代理队列中并立即返回。因此,由于它们的异步特性,它们不可能出现死锁。

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

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

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

当调度发生在代理末尾时,发送会将项目放入发送队列中并立即返回。由于代理永远不会阻塞等待资源,因此无法创建死锁循环。

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

存在竞争条件的可能性:来自不同线程的两次对send的调用可以“竞争”被放入代理的队列中,并且并发读取器可能会感知到不同的情况。 (稳定)值取决于他们何时读取代理的时间线。然而,这就是异步计算的本质。如果您希望在读取或写入多个资源时协调计算,则必须使用 refs

send and send-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) invoke send 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 correct send-off instead. The worker pool used by send-off is unbounded.

On sending within an action, the agents page states:

If during the function execution any other dispatches are made
(directly or indirectly), they will be held until after the state of
the Agent has been changed.

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.

友欢 2024-12-25 06:37:42

我不确定这是否可能,因为“发送”调用的异步性质可以防止此类死锁问题。如果发送是同步的,那么很容易就可以在发送函数中再次调用发送给同一个代理,现在如果是同步的,发送就会卡住。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文