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

能够更控制这一点会非常有用,希望不是通过简单的setter,就像我们在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实例。现在,本命名空间中声明的两个实例都是懒加载(延迟块内的),避免了无用的线程池初始化/泄漏。

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

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

0 投票

评论者:mpenet

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

我们可以允许在创建通道时传递一个executor,以便相对容易地对这个通道进行操作(部分示例在这里https://github.com/mpenet/core.async/commit/1449b3842052033cdf917ae92259ad9789722fdb

我相信这是manifold处理它的方式,但在这种情况下,我可能还有更多的未知因素。

0 投票

评论者:mpenet

包含chan修改的补丁。现在,channel可以接受一个额外的参数,这个参数将是一个和clojure.core.async.impl.protocols/Executor兼容的executor。如果提供了这个executor,那么它将用于全局默认池。

0 投票

评论者:mpenet

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

0 投票

评论者:gshayban

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

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

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

我非常欢迎对thread阻塞的executor有更多的控制。

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

0 投票

评论者:mpenet

嗨Ghadi,

感谢你的反馈,但我认为你没有正确阅读我的补丁。

我没有改变你提到的case(承诺),唯一改变的是,在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的案例?

关于这个问题有没有在开发列表上进行过讨论?

0 投票

评论者:mpenet

当然,只要这个问题得到改善/解决。

如果您阅读了这个补丁或相关通道的源代码,就会看到
通道在线程池上运行它们的回调。

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


0 投票
by

评论人: lxsameer

嗨,大伙儿,

我为threadpool ns添加了几個函数,以便用户为主线程池及thread宏提供一个执行器。

目前这是一个草稿,我想知道其他人对这个问题的看法,在花更多时间之前。请查看我repo中的commit https://github.com/Codamic/core.async/commit/5cfa3ac34f963dc67329722149d041629a6c6e6f,这应该能给你一些启发。
期待您的意见。

Cheers

by

再次阅读了我几年前创建的这个问题的细节后,现在我实际上同意Stu和Ghadi的评论,我认为我对core.async go内部的理解现在要好得多,在这个层面上的线程(和回调)仅仅是为了“监督”/上下文切换,因此对这些有非常细粒度的控制并不那么重要。

0 投票
我认为,仍有一个更好的thread-call函数的用例,也许还有一个像thread一样接受用户提供执行器的宏。

评论者:mpenet

是否考虑添加一个arity到thread-call补丁,以便传递执行器?

这个新thread-call arity的宏版本可以是什么形式(如果真的想要;我想,由于thread会接受一个body,这可能会有些困难,所以一个新的宏可能更合适)。

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

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