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

欢迎!请参阅关于页面以了解更多关于如何使用本站的信息。

0票数
 core.async

我对core.async(以及更广泛的CSP)是新手,正在努力找到良好的调试策略。特别是,我经常无法诊断代码的哪个部分无限期地阻止主线程。我将提供一个特定的例子

(deftest passing-test
  (let [c (async/to-chan! [2 1 0 5 4])]
    (is (= [2 1 0 5 4]
           (async/<!! (async/into [] c))))))


(deftest hanging-test
  (let [[e o] (->> (async/to-chan! [2 1 0 5 4])
                   (async/split even?))]
    (is (= [2 0 4]
           (async/<!! (async/into [] e))))
    (is (= [1 5]
           (async/<!! (async/into [] o))))))

第一个测试通过且不会阻塞主线程。第二个测试永久挂起。唯一的区别是添加了async/split以将偶数和奇数整数路由到各自的通道。

我的具体问题如下

  1. 是什么解释了第一个测试和第二个测试在阻塞主线程方面的差异?

  2. 有哪些策略可用于调试意外阻塞主线程的core.async代码?

  3. 编写单元测试的最佳方式是什么,以创建和操作通道?(async/<!! (async/into [] o))是否是一种将流过通道的值收集到集合的合理方式?

1 个答案

+1票数

选中
 
最佳答案

(1) 第二次测试的生产者一半放2,消费者(读取偶数)读取2;生产者放1,但消费者尚未消费奇数,所以生产者等待,从消费者的角度来看,偶数通道“永远不会关闭”,所以消费者停在了第一个<!!处。

(2) 停滞是最好的问题,因为你可以插入打印并找出停滞的原因。次优平衡更难弄清楚。

(3) 简单就是好。

非常感谢您的帮助!您对(1)的解释正是我所需要的。这看起来很重要,至少要了解一点底层事件序列。我最初的心理模型是`core.async`提供了一个声明式API。

关于您关于使用打印以确定问题的观点,我同意这听起来很理想,但我不知道如何实现。如果我正确理解了问题,我们应该在代码中添加一个打印语句,在该挂起之前打印一个`2`。是这样吗?您有这个可能的样子示例吗?

关于(3):同意这一点。

非常感激!
在重新阅读了一些资料并有了新的视角之后,我发现了一种添加调试打印语句的方法。我很想听听关于更简洁的方法。

  (let [[e o] (->> (async/to-chan! [2 1 0 5 4])
                     (async/split even?))]

      (async/go-loop []
        (when-let [x (async/<! e)]
          (println x)
          (recur))))
在粗略层面上,保持你原始的算法,你可以在每个`<!!`之前/之后放入一个打印,以判断哪个是阻塞的。
...