来自http://martintrojer.github.io/clojure/2013/07/07/coreasync-and-blocking-io/:
为了更具体一点,让我们看看当我们尝试发布时会发生什么 使用core.async的一些HTTP GET请求。让我们从天真开始吧 解决方案,通过clj-http使用阻塞IO。
(defn blocking-get [url] (clj-http.client/get url)) (time (def data (let [c (chan) res (atom [])] ;; fetch em all (doseq [i (range 10 100)] (go (>! c (blocking-get (format "http://fssnip.net/%d" i))))) ;; gather results (doseq [_ (range 10 100)] (swap! res conj (<!! c))) @res )))
这里我们尝试使用go获取90个代码片段(并行) 块(和阻塞IO)。这花了很长时间,那是因为 go块线程被长时间运行的IO操作“阻塞”。 通过将go块切换为正常可以改善这种情况 线程。
(time (def data-thread (let [c (chan) res (atom [])] ;; fetch em all (doseq [i (range 10 100)] (thread (>!! c (blocking-get (format "http://fssnip.net/%d" i))))) ;; gather results (doseq [_ (range 10 100)] (swap! res conj (<!! c))) @res )))
“长时间运行的IO操作会阻塞块线程”是什么意思?
答案 0 :(得分:6)
Go块旨在成为一种轻量级的合作线程;通过使用池中的几个线程并在 park 时切换块,例如在使用<!
等待通道时,它们提供比完整JVM线程更少开销的类似线程的行为。当您在阻塞JVM线程的块中调用方法时,线程切换不起作用,因此您很快就会耗尽JVM线程。大多数标准Java(和Clojure)IO操作将在等待时阻塞当前线程。
答案 1 :(得分:4)
“长时间运行的IO操作会阻塞块线程”是什么意思?
有限数量的线程专门用于服务块*。如果对其中一个线程执行阻塞I / O操作,则在该操作完成之前不能将其用于任何其他目的(除非线程被中断)。对于非去块线程(即,从thread
函数返回的线程)也是如此,但是非去块线程不是来自有限的去块线程池。因此,如果你在go块中阻塞I / O,那么即使线程没有做任何实际的工作(它只是在等待I / O),你正在“阻塞”块的线程被其他go块使用操作)。
*该数字当前恰好是42 + JVM可用的处理器数量。