0

process-async在框架内测试的功能midje会产生不一致的结果。大多数情况下,它会按预期进行检查,但有时会out.json以初始状态 ( "") 读取。在检查之前,我依靠async-blocker等待的功能process-async

我的方法有什么问题?

(require '[[test-with-files.core :refer [with-files public-dir]])

(defn async-blocker [fun & args]
  (let [chan-test (chan)]
    (go (>! chan-test (apply fun args)))
    (<!! chan-test)))

(defn process-async
  [channel func]
  (go-loop  []
    (when-let  [response  (<! channel)]
      (func response)
      (recur))))

(with-files [["/out.json" ""]]
    (facts "About `process-async"
           (let [channel (chan)
                 file (io/resource (str public-dir "/out.json"))
                 write #(spit file (str % "\n") :append true)]
             (doseq [m ["m1" "m2"]] (>!! channel m))
             (async-blocker process-async channel write)
             (clojure.string/split-lines (slurp file)) => (just ["m1" "m2"] :in-any-order)
             )
           )
    )
4

1 回答 1

1

问题是process-async立即返回“[...] 完成后将接收主体结果的通道”(因为go-loop只是语法糖(go (loop ...))go立即返回)。

这意味着阻塞将几乎立即具有一个值<!!,并且块从和执行async-blocker的顺序是不确定的。可能大多数情况下,块 from首先执行,因为它是首先创建的,但这在并发上下文中并不能保证。goprocess-asyncasync-blockerprocess-async

根据<!!它的文档“如果关闭将返回 nil。如果没有可用的将阻塞。” 这意味着,如果您可以假设 的返回值(apply fun args)是由 返回的通道go,您应该可以通过<!!以下方式使用阻塞:

(defn async-blocker [fun & args]
  (<!! (apply fun args)))

一旦通道中有值(即块的返回值),这将解除阻塞go

还有其他选项可以等待另一个go块的结果。例如,您可以将原始文件chan-test作为参数提供给fun,然后在创建的块终止时提供put一个值。但我认为,鉴于您显示的代码,其他方法可能会不必要地更加复杂。 chan-testgofun

于 2017-02-26T12:03:10.013 回答