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 相同的命名空间中,使其支持相同的接口,而不是使用原始的 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被调用的少数情况,即该函数在全局定义的线程池中运行,该线程池由除thread以外的core.async中的一切使用,它**可选地**可以通过提供的线程池函数参数来完成。默认值不变,如果您不传递执行器,则得到没有任何更改的当前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的情况吗?

有关于此的dev列表讨论吗?

0

评论由:mpenet

当然,只要这得到了改进/修复。

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

在提交此补丁时,我有时间与Timothy讨论过这个问题。
在IRC上与Baldridge交流并按照他的建议做了一些修改。既然你
可能与他共用办公室,建议你与他讨论当前的
方法,因为他比我们中任何人都更熟悉代码库。

0

评论者:lxsameer

嗨,大家好,

我在threadpool ns中添加了几个函数,以便用户可以为主线程池和用于 thread 宏的线程提供执行器。

目前只是一个草案,我想在花更多时间之前知道大家的意见。请查看
我仓库中的这个提交:

https://github.com/Codamic/core.async/commit/5cfa3ac34f963dc67329722149d041629a6c6e6f

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

加油

0

评论由:mpenet

重新阅读我多年前创建的这个问题的细节后,现在我实际上同意Stu和Ghadi的评论,我认为我对core.async go内部的了解现在要好得多,在这个级别(以及回调)的线程仅仅用于“监督”/上下文切换,所以对这些的精细控制并不那么重要。我认为我可能受到了manifold设计的启发,它在这些方面(以及其他方面)有很大差异,但这两个库有很大的不同。

我认为仍然有必要提供一个更好的线程调用函数,以及可能另一个类似的宏,它接受用户提供的执行器。

  • 能否考虑增加一个arity来tread-call,以便传递执行器?

  • 的这个新线程调用arity的宏版本可以采取什么形式(如果这是所需的;我认为创建一个新的宏更合理,因为thread接受一个&body,这可能有点难以 复位在那里)。

  • 能否考虑一个使各种threadpool初始化“懒惰的”(延迟的)补丁?

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