2024 Clojure 状况调查 中分享您的想法!

欢迎!请在 关于 页面上了解更多关于它是如何工作的信息。

+6
core.async
修改

你好!

我一直致力于修复 ASYNC-163 这个错误,我认为我找到了一个稳健的解决方案,不需要对 pipeline* 函数做太多改动。

我对向 Clojure 贡献还不熟悉,所以关于这个过程有点不确定,尽管我在 clojure.org 网站上已经了解过。关于这个问题已经有了存在的工单,我已经在上面链接了,但是它被标记为“不会修复”,我没有 Jira 账号去那里评论并发送补丁,所以我决定在这里发布。

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

我在这里附加了一个补丁,如果这个地方不适合这类问题,请随意指正。我已经在各种场景下测试了 REPL,并在我的一个使用常规 pipeline-async 的项目中进行了测试,它工作正常。此外,它还通过了使用 lein test 命令运行的 core.async 库的测试。

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

目前我遇到了一些问题在异步 . cljs 文件使用或是不使用我的补丁运行 CLJS 测试,但当我解决这个问题后,我会发布一个更新后的补丁,适用于 JVM 和 CLJS 运行时。

编辑:2022年11月25日

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

此补丁包含对 async.cljs 的相同修复,尽管由于某种原因我无法运行测试 - 在浏览器中我遇到了 "未捕获的类型错误:process.on 不是一个函数" 错误。不确定我遗漏了什么,项目的 readme 没有提到任何要求,除了用 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 内部使用的,创建了 exactly n 个任务,没有任何额外的,这解决了我在工作中遇到的问题。
这是一个问题。通过重新审视这个问题,您可以避免许多头痛。我可以回忆起一些亲身经历和间接经历,都因为这个原因而产生了一些意外的实际问题。意外的、未经记录的“偏两”并行性确实会以难以诊断的方式严重破坏您的系统。
“不会修复”的原始理由可能是对问题的一次疏忽或误解。当时解释说,“n”本应表示并行创建的进程数量,而不是运行的子进程。然而,对于创建本身来说,并行性毫无用处,因为创建本身总是一个常数时间操作。
> 那时解释说,“n”本应表示并行创建的进程数量,而不是运行创建的进程

有趣!但是, neither `pipeline` nor `pipeline-blocking` 都没有共享“偏两”错误并且正好创建 `n` 个并行进程。这是因为任务消费者线程没有将等待结果的工作卸载到另一个线程,而是自己完成。我的补丁更改了异步结果的等待方式,因此内部行为与阻塞和计算变体相同。
是的,Andrey,我只想指出,这个“不会修复”的案例可能是他们的误解。可能修复已经太晚了(因为用户代码已经通过调整偏两来解决这个问题)。但例如,用文档字符串指出问题的函数弃用,并提供正确版本,可以拯救未来的用户免于一些噩梦般的调试。
作为原始JIRA问题的作者,我感到有责任加入讨论,嘿嘿。我衷心同意lgrapenthin最后的评论。多年来,我遇到过几次人们对此行为感到困惑的情况。即使你接受了与其他管道函数相对的“并行”参数的不同含义(这就是“不会修复”状态所暗示的),我也看不出这对调用者有任何用处。也许我们在这里都遗漏了什么?

无论如何,如果这是最终决定,文档字符串至少应该以某种方式提及这一点,例如“with parallelism n,其中n不指代af的最大并行调用次数,而是X”(这里仍然不确定X应该填什么才能从用户的角度看有道理)。可以说,“pipeline”的文档字符串也可以相应修改,以便清楚地说明两种含义之间的区别,以免读者混淆。

尽管如此,我也宁愿弃用此功能,并以Andrey的实现作为其后继者(pipeline-async2?)。
...