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键。

我把thread执行器移到了与ioc/go相同的命名空间中,并使其支持相同的接口,而不是使用原始的j.u.c Executor实例。现在该命名空间中声明的实例都是懒加载的(在delay块中),从而避免了无用的线程池初始化/泄漏。

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

我将在不久后把.patch文件附在票据上。

0投票

评论者:mpenet

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

我们可以在频道创建时传递一个执行器,以便可以相对容易地对该频道上的操作强制执行该执行器(部分示例在此)。

我相信这也正是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

您好Ghadi,

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

我没有改变您提到的(承诺)的情况,唯一改变的是,在调用 clojure.core.async.impl.dispatch/run 的情况下,这意味着函数在核心.async 中除thread外所有内容使用的全局线程池中运行,可以**可选择地 通过提供的线程池函数参数完成。默认值保持不变,如果您不传递执行器,您将获得核心.async 当前主行为的当前行为,没有任何变化。

少数人提到了这种需求,有的公开,有的私下,包括我自己,我认识一个团队,他们表达过同样的担忧,因此将他们的一个系统从核心.async 切换到了 manifold,因为后者提供更多这种类型的控件。

最后,这关乎控制权,如果您不关心这个,对 core.async 和当前的执行模型没有任何影响,但对那些需要这种精细调整的人来说非常重要。

几天前,它又在推特上出现了一次:[https://twitter.com/puredanger/status/576378306062262272](https://twitter.com/puredanger/status/576378306062262272) ,你肯定也可以在 irc 日志中找到相关引用。

如果可能的话,我会将其作为库发布,但由于相关代码有时非常根深蒂固,几乎不可能不进行整个库的分支来完成,因此才有了这个补丁。

0投票

评论者:mpenet

与上一个补丁相同,添加了 promise-chan 中缺少的参数。

0投票

评论者:stu

将我的点赞视为对该问题的赞同,不一定是对这里采用的方法的赞同。

我认为 go 和 thread 是不同的情况,值得单独考虑。我不清楚为什么 chan 需要考虑,并且我不想在看过补丁(或了解 impl 命名空间)后发现原因。能否有人解释一下 chan 的案例,不涉及实现细节?

关于这个问题,在开发者列表中进行过讨论吗?

0投票

评论者:mpenet

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

如果你阅读了补丁,或者 channels 的源代码,你会看到
channels 在线程池中运行其回调。

在这个补丁提交时,我曾花时间与 Timothy 讨论过这个问题。
巴德利在IRC上提出了一些建议,我对这些建议进行了修改。由于你
可能和他共用办公室,我建议你和他讨论一下现有的
方法,因为他比我们俩都更熟悉代码库。

0投票
答案: by

评论者:lxsameer

大家好,

我在threadpool ns中添加了几个函数,以便允许用户为主线程池和对 thread 宏的executor进行提供。

目前,这只是一个草案,我想先知道其他人的看法,然后再花更多时间在这上面。请查看
我repo上的提交

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

它应该会给你一些想法。期待你的意见。

谢谢

0投票
答案: by

评论者:mpenet

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

我认为,仍然有必要有一个更好的thread-call函数,以及可能像thread一样的另一个宏,它接受用户提供的executor。

  • 是否可以考虑一个补丁,将bash参数添加到tread-call中,以便传递executor?

  • (如果需要的话)新的thread-call bash参数的宏形式可能是什么?

  • 一个使各种threadpool初始化“延迟”的补丁是否会被考虑?

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