请在 2024 Clojure 状态调查! 中分享您的想法。

欢迎!请参阅 关于页面 了解更多关于这里如何运作的信息。

+6
core.async
编辑

你好!

我一直在为一个 ASYNC-163 错误的修复工作,我认为我找到了一个无需对 pipeline* 函数做出太多改动的高效解决方案。

我刚开始为 Clojure 贡献,对这个过程还不太清楚,尽管在 clojure.org 网站上了解过。已经存在一个针对该问题的现有工单,上面的链接,它已被关闭,标注为“不修复”,我没有 Jira 账户在上面评论和发送补丁,所以我决定在这里发布。

通过研究 pipeline* 函数的源代码,我理解了工作是如何在 go-threads 和 channels 之间传递的整个过程,并找到一个非常简单的修复方法,这只需要为同步任务生产者和结果消费者线程添加一个额外的通道。
我在博客中对我的博客中的一篇更详细的错误解释。它相当长且复杂,所以我认为我最好不要在这里重复,以免使问题变得不必要地长并且更难以理解。解释在这里可以找到 这里

我在这里附加了一个补丁,如果您觉得这个地方不是这类问题的合适之地,请随时指出。我已经在不同的场景下以及在多个项目中测试了它,这些项目使用了常规的 pipeline-async,它运行正常。此外,它通过了我运行的 core.async 库的测试,这是通过 lein test 命令进行的。

补丁:https://andreyorst.gitlab.io/0001-fix-ASYNC-163.patch

目前我在运行带或不带我的补丁的 async.cljs 文件的 CLJS 测试时遇到了一些问题,但我一旦找到问题,会发布更新的补丁,针对 JVM 和 CLJS 运行时。

编辑:2022-11-25

补丁 v2:https://andreyorst.gitlab.io/0001-fix-ASYNC-163-2.patch

该补丁包含了针对 async.cljs 的相同修复,尽管由于某种原因我无法运行测试 - 在浏览器中我遇到了 Uncaught TypeError: process.on is not a function 错误。不确定我错过了什么,项目的说明文件中没有提到除了使用 lein 构建 和打开 HTML 文件之外的任何要求。但修复基本上是相同的,所以应该可以正常工作。

编辑日期:2022年12月08日

我将修复后的 pipeline* 版本放入了一个名为 pipeline-extras 的库中。它还包含了所有流程的无序版本,这应该会有更高的吞吐量,因为如果任何任务完成的时间比其他任务长,传送带不会停止。

1 答案

0
by

嗨,那里的“不会修复”是为了表示我们不认为这是一个问题,并且不需要修复。

by
编辑 by
但是,当访问一个可以服务有限数量的连接的服务时,这确实是一个问题。

在我们的产品中,我们有一个配置为接受最多10个并发连接的服务。

编写

(pipeline-async 10 out-chan request-fn in-chan)

创建了12个连接而不是10个,这导致服务开始拒绝连接。这是一个意外的错误。

所以,在所有使用 pipeline-async 函数的代码中,我们必须做 (- *max-requests* 2),以避免创建服务接受的更多连接。

我附加的补丁确保 pipeline* 函数(这是 pipeline-async 内部使用的函数)创建的操作任务正好是 n 个,而不仅仅是更多,这解决了我工作中遇到的问题。
这是一个问题。通过重新审视这个问题,你可以避免很多令人头痛的事情。我记得有几个亲身经历和道听途说,这个错误在不经意间造成了意外的实际问题。意外的未记录的偏移量为2的并允许真的会在诊断困难的方式中打乱 你的系统。
不修复原始的理由可能是因为对问题的忽视或误解。然后解释说`n`原本是想指定并行生成的数量,而不是运行生成的进程。然而,对于生成本身,并行性没有任何用途,因为生成总是一个常数时间操作。
> 那时解释说 `n` 应该是并行生成数量的标识,而不是运行的生成进程数量。

很有趣!然而,`pipeline` 和 `pipeline-blocking` 都没有`偏移量为2`的错误,并且会精确生成 `n` 个并行进程。这是因为作业消费者线程没有将等待结果的负担卸载到另一个线程,而是自己完成。我的补丁改变了异步结果等待的方式,所以内部行为与阻塞和计算 Variant 相同。
是的,Andrey,我只是想提醒Alex,他们方面这个wontfix案例可能是一个误会。或许已经太迟修复(因为用户代码已经通过这个错误计算了偏移量)。但例如,通过文档字符串指出问题并提供一个正确版本,可以防止未来的用户陷入一些噩梦般的调试过程中。
作为原始JIRA问题的作者,我认为我有责任发表意见,呵呵!我强烈同意lgrapenthin的最后一个评论。多年来,我遇到过几次人们对这种行为的困惑。即使你接受“并行性”与其他管道函数不同的含义(这也意味着“不会再修复”的状态),我也看不出这对调用者有任何实际帮助。或许我们在这里都忽略了什么?

无论如何,如果这是最终决定,文档字符串至少应该以某种方式提到这一点,例如:“with parallelism n(其中n不表示af的最大并行调用次数,而是X)”(在这里填入X确实是用户角度上的100%不明确,所以它听起来有道理)。可以说,“pipeline”的文档字符串也可以相应地修改,以明确两种含义,以免读者混淆。

话虽如此,我也更喜欢废弃这个函数,并让Andrey的实现(pipeline-async2?)作为继任者。
...