2024年Clojure调查!中分享您的想法。

欢迎!请查看关于页面以获取更多关于此工作的信息。

0投票
core.async

目前core.async使用的线程池被定义为全局的,它们被各自的go或thread宏所共享。

请参阅https://github.com/clojure/core.async/blob/ac0f1bfb40237a18dc0f03c0db5df41657cd23a6/src/main/clojure/clojure/core/async.clj#L391-L411
以及https://github.com/clojure/core.async/blob/ac0f1bfb40237a18dc0f03c0db5df41657cd23a6/src/main/clojure/clojure/core/async/impl/dispatch.clj#L16

能对这方面有更多控制将非常有用,希望不是通过像core中agent(set-agent-send-executor!)那样的简单setter,因为它一次只允许使用一个线程池。
一个可行的解决方案可能是通过thread-call的选项映射参数以及go块(具有相同签名的go-call)的其他机制来实现。将此参数作为映射也可以在需要时允许进一步扩展内部机制,而无需对API进行重大更改。

12 答案

0投票

评论由:mpenet发布

我有一个补丁在这里https://github.com/mpenet/core.async/commit/1c2b0a9af9a5e891af0f1631b8debd337a73999d,它添加了此功能。

它增加了2个宏:go*和thread**。这些与go/thread相同,但首先需要一个选项映射,然后是主体。选项映射可以接收一个带有clojure.core.async.impl.protocols/Executor实现的:executor键。

我授权将thread执行器移动到与ioc/go相同的命名空间中,并支持相同的接口,而不是使用原始的j.u.c Executor实例。在此命名空间中声明的这两个实例现在是懒加载的(在一个延迟块中),防止了无用的线程池初始化/泄漏。

最后,我还修改了thread-call以支持相同的选项映射。

我将很快将该.patch文件附加到票据上。

0投票
by

评论由:mpenet发布

实际上这个补丁是不完整的,我刚刚发现ioc-macros重写会导致对全局线程池的调用(尤其是通过put(image: , take)回调)。

我们可以在创建通道时传递一个执行器,以便相对容易地将此通道上的操作强制运行在该执行器上(部分示例见https://github.com/mpenet/core.async/commit/1449b3842052033cdf917ae92259ad9789722fdb)。

我相信这也是manifold处理它的方式,但目前我可能还有更多未知因素。

0投票
by

评论由:mpenet发布

包含chan修改的补丁。现在chan可以接收一个额外的参数,该参数是一个clojure.core.async.impl.protocols/Executor兼容的执行器,如果提供了这个执行器,它将替换全局默认池来使用。

0投票
by

评论由:mpenet发布

作为单一提交提供补丁(更易于阅读)。您还可以在此查看更改:https://github.com/mpenet/core.async/commit/e7dea04553935863d1abb1880d84bbdc273854ec

0投票
by

评论者:gshayban

嗨,Max。我认为有必要对此进行更好的控制。

基本上有两个需求
1)回调需要唤醒停泊的go-blocks。
2)运行更重的thread(可能阻塞,因此不能与同一个池共享)

目前通道回调不知道它们唤醒了什么。我认为这是一个好的设计。如果它们唤醒一个线程,那只是通过交付一个承诺间接做到的(链接:1)
我认为channels.clj中不应提及特定的执行器。在多个不同位置运行go-blocks可能是一个反模式,因为go-blocks不应该阻塞或进行I/O。

我非常欢迎一些对thread块执行器的控制。

(链接:1) https://github.com/clojure/core.async/blob/master/src/main/clojure/clojure/core/async.clj#L137

0投票

评论由:mpenet发布

嗨 Ghadi,

感谢您的反馈,但我不认为您正确阅读了我的补丁。

我没有更改您提到的案例(promise),唯一改变的是,对于clojure.core.async.impl.dispatch/run被调用的少数情况,这意味着该函数在一个全局定义的线程池中运行,该线程池用于core.async的所有内容(除了thread),它可以通过一个带参数的线程池函数选择性地执行。默认值不变,如果您不传递执行器,将得到核心.async当前行为的不变版本。

一些人提到了需要,有些公开讨论,有些私下讨论,包括我自己,我得知有一个团队表达了相同的担忧,他们已经将系统从一个转换到另一个,从core.async到manifold,因为后者提供了更多类似的控制器。

最后,关乎控制,如果您对此不感兴趣,它不会改变core.async及其当前执行模型,但它对于那些需要这种精细调整的人来说很重要。

几天前在twitter上再次出现了这个问题: https://twitter.com/puredanger/status/576378306062262272,您也可以在irc日志中找到相关参考。

如果可能,我会将其作为库发布,但相关的代码有时非常深入,几乎不可能在不分叉整个库的情况下进行更改,所以有了这个补丁。

0投票

评论由:mpenet发布

与之前的补丁相同,为promise-chan添加了缺失的arity。

0投票

由stu发表的评论:

我将我的投票视为对问题的支持,而不一定是针对这里采取的方法。

在我看来,go和thread是两个不同的案例,应该分别考虑。我不清楚为什么要用chan考虑,我不想在阅读补丁(或了解impl命名空间)之前就能发现原因。能否有人在不参考实现的情况下解释chan的案例?

关于这个话题在开发者列表上有讨论吗?

0投票

评论由:mpenet发布

当然,只要这个问题得到改善或修复。

如果您阅读了补丁或通道的源代码,您将看到
通道在线程池中运行它们的回调。

在这个补丁被提交时,我花了时间在IRC上与Timothy Baldridge讨论这个问题,并按照他的建议进行了一些修改。
鉴于您可能与他同一个办公室,我建议您与他讨论当前的方案,因为他比我们中的任何人都更熟悉代码库。


0投票

评论者:lxsameer

大家好,

我在threadpool命名空间中添加了一些函数,以便允许用户为主线程池和thread宏提供执行器。

这只是一个草案,我想在花更多时间之前知道其他人的意见。请检查我在以下仓库的提交:
https://github.com/Codamic/core.async/commit/5cfa3ac34f963dc67329722149d041629a6c6e6f

这应该能给您一些启发。期待您的意见。

敬礼

0投票

评论由:mpenet发布

在重新阅读我多年前创建的此问题的详细信息后,我现在实际上同意Stu和Ghadi的评论,我认为我对core.async go内部的了解现在要好得多,在这么低的层面上进行线程(和回调)仅用于“监管)/上下文切换,所以对这些内容进行细粒度控制并不那么重要。

我认为仍有必要有一个更好的线程调用函数,可能还有一个像thread那样的用户提供的执行器宏。

  • 是否可以将具有通过执行器传递能力的arity添加到tread-call补丁中,以便考虑?

  • 如果有人希望有一个宏版本的新线程调用arity,它可能的形式是什么?(我认为一个新的宏会比thread更合适,因为thread需要一个&body,可能在那里难以改进)。

  • 是否可以考虑使各种线程池初始化变得“延迟”(延迟)?

0投票
参考: https://clojure.atlassian.net/browse/ASYNC-94(由 mpenet 提出)
...