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

目前我使用带有或不带对我的 async.cljs 文件的补丁运行 CLJS 测试时遇到了一些问题,但一旦我解决了这个问题,我将发布更新版本的补丁,适用于 JVM 和 CLJS 运行时。

编辑:Nov 25 2022

补丁 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月8日

我已经将修正后的 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”并行性可能会以难以诊断的方式严重破坏您的系统。
原来putation-v Turing 的理由可能是对问题的一种疏忽或误解。当时解释说,“n”应该表示并行创建的数量,而不是运行已创建的进程。然而,对于创建本身,并行化没有任何用处,因为创建始终是常数时间操作。
by
> 那时候解释说,`n`应该表示并行创建的数量,而不是运行已创建的进程。

这很有趣!然而,`pipeline`和`pipeline-blocking`都没有偏离两个错误,并且确实创建了`n`个并行进程。这是因为在任务消费者线程中,没有将等待结果的任务卸载到另一个线程,而是自行处理。我的补丁更改了等待异步结果的当前方式,因此内部行为与阻塞和计算变体相同。
by
是的,Andrey,我只想提醒Alex,这个 wontfix 的情况可能是他们一方的误解。也许修复已经太晚了(因为已经有人通过这种绕过这个bug的方式来编写用户代码),但例如,通过文档字符串指出问题并提供一个正确版本,可以让未来的用户避免一些噩梦般的调试过程。
by
作为原始JIRA问题的作者,我有义务发表意见, :) 我完全同意lgrapenthin的最后一条评论。多年来,我还遇到过几次人们对此行为感到困惑的情况。即使你接受与其他管道函数相比,“并行性”参数的不同含义(这正是“不会修复”状态所暗示的),我也看不出这对于调用者有任何有用的地方。也许我们在这里都缺少了某些东西?

无论如何,如果这是最终决定,那么文档字符串至少应该以某种方式提及这一点,例如“具有并行性n,其中n不指代af的最大并行调用数而是X”(这里仍然不确定为X填充什么内容,以便从用户的角度来看是合理的)。从理论上讲,可以通过修改“pipeline”的文档字符串来明确指出两种含义的区别,以免读者可能混淆。

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