在core.async中阻止vs线程

时间:2015-05-20 17:29:49

标签: multithreading clojure core.async

来自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操作会阻塞块线程”是什么意思?

2 个答案:

答案 0 :(得分:6)

Go块旨在成为一种轻量级的合作线程;通过使用池中的几个线程并在 park 时切换块,例如在使用<!等待通道时,它们提供比完整JVM线程更少开销的类似线程的行为。当您在阻塞JVM线程的块中调用方法时,线程切换不起作用,因此您很快就会耗尽JVM线程。大多数标准Java(和Clojure)IO操作将在等待时阻塞当前线程。

答案 1 :(得分:4)

  

“长时间运行的IO操作会阻塞块线程”是什么意思?

有限数量的线程专门用于服务块*。如果对其中一个线程执行阻塞I / O操作,则在该操作完成之前不能将其用于任何其他目的(除非线程被中断)。对于非去块线程(即,从thread函数返回的线程)也是如此,但是非去块线程不是来自有限的去块线程池。因此,如果你在go块中阻塞I / O,那么即使线程没有做任何实际的工作(它只是在等待I / O),你正在“阻塞”块的线程被其他go块使用操作)。

*该数字当前恰好是42 + JVM可用的处理器数量。