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

欢迎!请参阅关于页面,了解此工作的更多信息。

+6
core.async
编辑

你好!

我正在修复ASYNC-163 漏洞,我认为我已经找到了一个稳健的解决方案,不需要对 pipeline* 函数做出太多修改。

我对为Clojure做出贡献比较新手,所以我对过程有点不确定,尽管我在clojure.org网站上读了一些东西。问题已经有一个现成的工单,我在上面链接了,然而它已被标记为“不会修复”,我没有Jira账户在那里进行评论和发送补丁,所以我决定在这里发布。

通过研究 pipeline* 函数的源代码,我了解了将工作在go线程和通道之间传递的整个过程,并找到了一个简单的修复方法,它需要添加一个额外的通道来同步工作生成器和结果消费者线程。
我在我的博客中对这个漏洞进行了更详细的解释。它相当长且复杂,因此我认为最好在这里不重复它,以免使这个问题变得过于冗长和难以理解。解释在这里可用。

我在这里附上了补丁,如果这个地方不适合这类问题,请随时指出。我在REPL中测试了各种场景,并在我的一个项目中,它使用标准的 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 错误。不清楚缺少了什么,项目的README只提到除了使用 lein 构建和打开 HTML 文件之外的任何要求。但是修复本质上相同,所以应该运行良好。

编辑于 2022 年 12 月 08 日

我将修复后的 pipeline* 版本放入了一个名为 pipeline-extras 的库中。它还包含了所有管道的无序版本,由于即使某些任务完成时间比其他任务长,传送带也不会停止,因此应具有更高的吞吐量。

1 答案

0

你好, “不会修复”那是为了表示我们不认为这是一个问题,也不认为它需要修复。


编辑了
当访问一个只能处理有限连接数量的服务时,这是一个问题。

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

编写

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

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

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

我附加的补丁确保 pipeline* 函数(pipeline-async 内部使用)创建的确切任务数为 n,而不仅是更多,这修复了我在工作中遇到的问题。
by
尽管这是一个问题。通过重新审视这个问题,你可以节省世界无数个头疼的问题。我可以回忆起很多亲身经历和间接经验,这些问题都是在未经文档记录的情况下创建的意外的真实世界问题。意外的未记录的“偏差2”并行性可能会以难以诊断的方式真的困扰你的系统。
不会修复的原始理由可能是对问题的一种疏忽或误解。当时解释说,`n`本应该代表并行_spawn的数量,而不是运行_spawn出的进程。然而,对于_spawn自身来说,并行性没有任何作用,因为_spawn始终是一个常数时间操作。
by
> 然后解释说,`n`本应该代表并行_spawn的数量,而不是运行_spawn出的进程

有趣!但是,`pipeline`和`pipeline-blocking`都没有“偏差2”错误,而是正好_spawn出`n`个并行进程。这是因为工作消费者线程不会将等待结果的任务卸载到另一个线程,而是自己完成。我的补丁改变了异步结果的等待方式,因此内部行为与阻塞和计算变体相同。
by
是的,Andrey,我只是想提醒Alex,这个不会修复的情况可能是他们方面的误解。可能修复得太晚了(因为用户代码已经绕过这个bug并考虑了偏差2)。但是,例如,通过带有指出现有问题的文档字符串来弃用函数,并提供一个正确的版本,可以节省未来用户从一些噩梦般的调试会话中解脱出来。
作为原始JIRA问题的作者,我有责任发表意见,嘿嘿。我完全同意lgrapenthin的最后一条评论。多年来,我也遇到过一些人对此行为感到困惑的情况。即使你接受与其他管道函数相比,“parallelism”参数的不同含义(这是“wontfix”状态所暗示的),我也看不出这对调用者有任何用途。也许我们在这里都忽略了什么?

无论如何,如果是最终结论,文档字符串至少应该以某种方式提到这一点,例如:“with parallelism n,其中n不指代af的最大并行调用数,而是X”(这里X的填充还不够100%,以确保从用户的视角来看是有意义的)。可能需要相应修改“pipeline”的文档字符串,以明确两种含义之间的区别,以免读者混淆。

话虽如此,我也更喜欢弃用此函数,并由Andrey的实现(pipeline-async2?)作为替代者。
...