核心.async中的go块和线程的区别

9

来自http://martintrojer.github.io/clojure/2013/07/07/coreasync-and-blocking-io/

To get a bit more concrete let's see what happens when we try to issue some HTTP GET request using core.async. Let's start with the naive solution, using blocking IO via clj-http.

(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
       )))

Here we're trying to fetch 90 code snippets (in parallel) using go blocks (and blocking IO). This took a long time, and that's because the go block threads are "hogged" by the long running IO operations. The situation can be improved by switching the go blocks to normal threads.

(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操作会占用Go语言中的阻塞线程”,因此会影响应用程序的性能。

1
那个链接似乎已经失效了。这个可以用:https://martintrojer.github.io/clojure/2013/07/07/coreasync-and-blocking-io(去掉末尾的斜杠) - Arne Brasseur
2个回答

6

Go块通常被视为轻量级协作线程;它们提供类似于线程的行为,比完整JVM线程的开销更小,通过使用池中的几个线程,并在等待通道时通过<!切换go块。当您在块中调用阻塞JVM线程的方法时,线程切换无法工作,因此您很快就会耗尽JVM线程。大多数标准Java(和Clojure)IO操作在等待时会阻塞当前线程。


我原以为Clojure也会使用ForkJoin,但看起来它并没有。它使用一个简单的FixedThreadpool。这是有原因的吗?Scala可以使用forkjoins,甚至可以告诉执行器它是阻塞代码,以便建议生成更多线程。(http://docs.scala-lang.org/overviews/core/futures.html)和(http://dev.clojure.org/display/design/Async+Executor) - ClojureMostly

4
“go block线程被长时间运行的IO操作占用”是什么意思?
系统中有一定数量的线程专门用于服务go block。如果您在其中一个线程上执行阻塞I/O操作,则该线程在该操作完成之前无法用于任何其他目的(除非该线程被中断)。这对于非go block线程也适用(即从“thread”函数返回的线程),但非go block线程不来自有限的go block线程池。因此,如果您在go block中进行阻塞I/O,则会将该go block的线程“独占”,防止其他go block使用该线程,即使该线程没有实际工作要做(只是等待I/O操作)。
*该数字目前恰好为42 + JVM可用处理器的数量。

3
抱歉打扰了,但是这个不是2+可用处理器吗?不是42+...? - Carcigenicate
go-block线程池是每个进程、每个JVM还是每台机器? - tar
进程级别和 JVM 级别的区别是什么? - erikprice

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接