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 测试时,无论是否包含对 async.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 日

我将 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 个任务,而不是更多,这解决了我在工作中遇到的问题。
by
不过这是一个问题。通过重新审视这个问题,你可以避免世界上的许多烦恼。我记得有几个第一手和第二手的经验表明,这个问题在不经意间造成了意外的实际世界问题。意想不到且未经记录的“加减2”并行问题会以难以诊断的方式真正搞乱你的系统。
不修复这个问题的原始理由可能是对问题的另一个疏漏或误解。当时解释说,“n”本应指代并发的数量,而不是运行的子过程量。然而,本身并发没有实际用处,因为创建子进程总是常数时间的操作。
by
当时解释说,“n”本应指代并行创建的数量,而不是运行创建的进程。

有趣!然而,“pipeline”和“pipeline-blocking”都没有“加减2”错误,并且恰好创建“n”个并行进程。这是因为在你的任务消费者线程中,没有把等待结果的任务卸载给另一个线程,而是自己完成。我的补丁改变了异步结果等待的方式,因此内部行为与阻塞和计算变体相同。
by
是的,Andrey,我只是想指出给Alex看,这种情况的不修复可能是他们那里的一处误解。可能修复已经太晚了(因为用户代码已经绕过这个错误并考虑了加减2)。但是,例如,通过添加一个表明问题的文档字符串并提供一个正确的版本,可以拯救未来的用户免于一些噩梦般的调试会话。
by
作为原始JIRA问题的作者,我感到有必要发表自己的看法,当然也是一样的观点 :-) 我完全同意lgrapenthin的最后一个评论。多年来,我也遇到过这种情况,人们对此行为感到困惑。即使你接受相对于其他管道函数的"并行性"参数的不同含义(即"不会修复"的状态所暗示的),我也看不出这对调用者有任何用途。也许我们在这里都错过了什么?

无论如何,如果这是最后的决定,至少文档应该以某种方式提及这一点,例如:“带有并行性n,其中n不指最大的af并行调用次数但X”(仍然不确定在这里填写X,以便从用户的观点看是有意义的)。可以说,"pipeline"的文档字符串也应该相应修改,以明确两者之间的区别,以免读者混淆。

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