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

欢迎!请参阅关于页面以获取更多关于如何使用它的信息。

0投票
core.async

目前由core.async使用的线程池被定义为全局变量,它们由对应池中的所有go或线程宏共享

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中为代理(set-agent-send-executor!)所使用的简单设置器,因为它一次只允许使用一个线程池。
一个可能的解决方案是通过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键。

我自行为此移动了与 ioc/go 同一个命名空间中的 thread 执行器,并使其支持相同的接口,而不是使用原始的 j.u.c Executor 实例。现在该命名空间中声明的两个实例现在是延迟(在一个延迟块中)的,这样可以避免无用的线程池初始化/泄漏。

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

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

0投票

由:mpenet发表的评论

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

我们可以在创建管道时传递一个执行器,使得对该管道的操作相对容易地运行在那里(这里有一个部分示例 https://github.com/mpenet/core.async/commit/1449b3842052033cdf917ae92259ad9789722fdb)。

我相信 manifold 也是这样处理的,但这个阶段对我来说可能还有更多的未知因素。

0投票

由:mpenet发表的评论

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

0投票

由:mpenet发表的评论

作为一个单独的提交提供补丁(更易读)。您也可以在这里查看更改: https://github.com/mpenet/core.async/commit/e7dea04553935863d1abb1880d84bbdc273854ec

0投票

评论者:gshayban

嗨,Max。我认为对此有一些更好的控制是必要的。

基本上有两个需求
1) 回调需要唤醒已停用的 go-block。
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以外的所有部分使用的全局定义的线程池中运行,它可以通过一个提供的线程池函数参数***可选 地进行,默认值不变,如果你不传递执行者,你将获得没有任何改变的当前master core.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发表的评论

当然,只要这个问题被改进或修复。

如果您阅读了补丁或通道的源代码,您会看到
通道在其线程池上运行回调。

当这个补丁被提交时,我与Timothy Baldridge在IRC上讨论了这个问题,并根据他的建议进行了一些修改。
由于你可能和他共用办公室,我建议你和他的当前方法进行讨论,因为他比我们两个都更熟悉代码库。

我知道你的意见。

0投票

评论者:lxsameer

大家好,

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

目前这是一个草案,我想在进一步投入更多精力之前知道其他人的意见。请查阅我repo上的提交
https://github.com/Codamic/core.async/commit/5cfa3ac34f963dc67329722149d041629a6c6e6f

它应该给出了想法。期待您的意见。

再见

0投票

由:mpenet发表的评论

在重新阅读我多年前创建的这个问题细节后,我现在实际上同意Stu和Ghadi的评论,我认为我对core.async go内部的理解现在要好得多,在这个级别上(和回调)的线程处理仅仅是用于“监督”/上下文切换,所以对这些事物的细粒度控制并不重要。

我认为还存在一个更好的thread-call函数和类似于thread的另一个宏,这个宏接受用户提供的执行器的案例。

  • 如果能考虑为一个添加了参数的thread-call添加补丁以允许传递执行器吗?

  • 如果有人想要一个新的宏,那么这个新的thread-call参数可以采取什么形式(如果确实需要的话;我认为一个新的宏更合适,因为thread接受一个&body,这可能在回滚那里有些棘手)。

  • 如果一个使各种threadpool初始化“延迟”的补丁被考虑,会怎么样吗?

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