请参与 2024 年 Clojure 使用状况调查!

欢迎!有关如何使用本网站的更多信息,请参阅关于页面。

+6
core.async
编辑

大家好!

我已经为 ASYNC-163 问题开发了一个修复方案,并相信这提供了一个不需要对 pipeline* 函数进行太多更改的强大解决方案。

我刚开始为 Clojure 做贡献,所以我对这个过程有些不确定,尽管我在 clojure.org 网站上已经阅读了相关信息。已经存在一个针对该问题的工单,我上面已经提供了链接,但它已被标记为 "不予修复",我没有 Jira 账户在上面评论并发送补丁,所以我决定在这里发布。

通过研究 pipeline* 函数的源代码,我了解了工作如何在 go-threads 和 channels 之间传递的整个过程,并且找到了一个简单的修复方案,它需要添加一个额外的频道来同步生产者线程和消费者线程。
我在自己的博客中详细解释了这个错误。内容有点长,因此我认为最好在这里不重复,以免使问题变得过于冗长和难以理解。解释可在此处找到此处

我这里附加了一个补丁,如果这个地方不适合这种类型的问题,请随时告诉我。我已经在 REPL 中用各种场景测试过,以及在用我的补丁修改的 async.cljs 文件的一个项目中进行测试,它在那里运行正确。此外,它通过了在 core.async 库中运行的测试,我使用 lein test 命令进行了运行。

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

目前我在使用或不用我的补丁运行 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。不确定遗漏了什么,该项目的 README 文件没有提及除了使用 lein 构建 和打开 HTML 文件之外的任何要求。但由于修正本质上相同,所以应该可以正常工作。

编辑日期 2022 年 12 月 08 日

我将 fixes 版本的 pipeline* 放入了一个库 pipeline-extras。它还包括所有管道的非顺序版本,这些版本应具有更高的吞吐量,因为传送带不会因为任何任务完成时间比其他任务长而停止。

1 答案

0
by

嗨,那里的 "won't fix" 是用来表示我们并不认为这是一个问题,也不认为它需要修复。

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`个并行进程。这是因为工作消费者线程没有将等待结果的负担卸载到另一个线程,而是自己处理。我的补丁更改了异步结果等待的方式,因此内部行为与阻塞和计算变体相同。
是的,Andrey,我只是想指出,这个不会修复的情况可能是他们方面的误解。可能已经太晚修复了(因为用户代码已经绕过这个错误并考虑到偏离2)。但例如,通过文档字符串指出问题并提供一个正确的版本,可以让未来的用户避免一些噩梦般的调试会话。
作为原始JIRA问题的作者,我感觉有责任参与其中,嘿嘿。我完全同意lgrapenthin的最后一条评论。多年来,我遇到过几次人们也被这种行为所困惑。即使你接受“并行性”参数与其他管道函数不同的含义(这正是“不会修复”状态所暗示的),我也看不出这对调用者有任何帮助。也许我们在这里都遗漏了某些东西?

无论如何,如果这是最终的决定,文档字符串至少应该以某种方式提及这一点,例如,“带有并行性n,其中n不指代af最大并行调用次数,而是X”(这里仍不确定要填什么X才能从用户的观点来看是有意义的)。可以说,“pipeline”的文档字符串可以根据此进行相应修改,以明确这两种含义的区别,以免读者混淆。

话虽如此,我也宁愿废弃这个函数,并且有Andrey的实现作为接班人(pipeline-async2?)。
...