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
by
被选中 by
 
最佳答案

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

(2) 挂起是最好解决的问题是,因为你可以在代码中插入打印语句来找出原因。次优平衡要难以搞清。

(3) 越简单越好。

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

关于你提到的(2)中的使用打印语句来识别问题,我同意这听起来很理想,但我不确定如何实现。如果正确理解问题,我们应该能够在代码的某个位置添加一个打印语句,打印出在挂起之前的 `2`。是这样吗?你能提供一个这样的例子吗?

关于(3):阿门,这就是。

非常感激!
by
重新阅读了一些新材料后,我找到了一种添加调试打印语句的方法。我很想听听更有针对性的建议。

  (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))))
by
在粗粒度上,保持您的原始算法,您可以在每个 `` 前后放置一个 `print` 来判断哪个是阻塞的。
...