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来将偶数和奇数整数路由到它们各自的channel。

我的具体问题是以下这些:

  1. 什么解释了第一个和第二个测试在阻止主线程方面的不同?

  2. 有哪些调试意外阻止主线程的核心.async代码的策略?

  3. 编写为创建和操作channels的代码的单元测试的最佳方式是什么?(async/<!! (async/into [] o))是否是收集通过channel流动的值的合理方式?

1 个答案

+1

被选为最佳答案
 
最佳答案

(1) 第二次测试的生产者部分放入2,消费者(读取偶数)读取2;当生产者放入1时,但消费者尚未-consuming 奇数,所以生产者等待,从消费者的角度来看,偶数通道“永远不会关闭”,因此消费者停滞在第一个 <!!

(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))))
在粗略层面上,保持您的原始算法,您可以在每个`<!!`前面/后面放置一个打印语句,以判断哪个是阻塞的。
...