请在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中为agents(set-agent-send-executor!)那样的简单设置器,因为它一次只允许使用一个池。
一个可能的解决方案是通过thread-call的选项映射参数来这样做,以及go块的其它机制(带相同签名的go-call)。将这个参数设为映射也会在未来必要时进一步扩展内部结构,而无需对API进行重大更改。

12 个答案

0

评论者:mpenet

我这里有一个补丁https://github.com/mpenet/core.async/commit/1c2b0a9af9a5e891af0f1631b8debd337a73999d,它增加了这个特性。

它添加了两个宏:go*和thread**。这两个宏与go/thread相同,但是首先接受一个选项映射,然后是正文。选项映射可以接受有一个键为:executor,值为一个clojure.core.async.impl.protocols/Executor实现。

我擅自将thread执行器移动到与ioc/go相同的名称空间中,并使其支持相同的接口,而不是使用原始的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-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

Hi 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缺少的参数数。

0

由 stu 发表的评论:

将我的赞扬视为对问题的赞赏,而不一定是此处采取的方法。

在我看来,go和thread是不同的案例,值得单独考虑。我不清楚为什么chan需要考虑,我不希望不得不阅读补丁(或了解impl命名空间)来了解原因。能否有人不涉及实现来解释chan的案例?

关于这个问题是否有开发者列表的讨论?

0

评论者:mpenet

当然,只要这个改进/修复得到完成。

如果您阅读补丁或网络的代码,您会看到
网络在其线程池上启动回调。

当这个补丁被提交时,我花费了一些时间在IRC上与Timothy Baldridge讨论并做出了一些修改。因为您
可能与他同在一个办公室,我建议您与他讨论当前的
方法,因为他比我们任何人都更熟悉代码库。

0

评论由:lxsameer 创建

大家好,

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

目前这是一个草案,我想知道大家对它的看法,然后再花费更多时间。请检查
我的仓库中的提交,网址为

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

这应该会让你有一个概念。期待您的意见。

再见

0

评论者:mpenet

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

我认为有一个更好的thread-call函数,以及可能另一个像thread那样的宏,它接受用户提供的执行器,是合理的。

  • 添加到thread-call函数的一个参数以允许传递执行器的补丁会被考虑吗?

  • 那个新thread-call参数的新宏版本会是什么形式(如果这是想要的;我认为一个新的宏更有意义,因为thread接受一个&body,可能会有点难以下设)。

  • 使各种threadpool初始化“滞后”(延迟)的补丁会被考虑吗?

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