do块中作业数量的上限?

时间:2015-05-20 17:47:08

标签: multithreading clojure core.async

以下是代码:

(ns typedclj.async
  (:require [clojure.core.async
             :as a
             :refer [>! <! >!! <!!
                     go chan buffer
                     close! thread
                     alts! alts!! timeout]]
            [clj-http.client :as -cc]))


(time (dorun
        (let [c (chan)]
          (doseq [i (range 10 1e4)]
            (go (>! c i))))))

我收到了一个错误:

Exception in thread "async-dispatch-12" java.lang.AssertionError: Assert failed: No more than 1024 pending puts are allowed on a single channel. Consider using a windowed buffer.
(< (.size puts) impl/MAX-QUEUE-SIZE)
    at clojure.core.async.impl.channels.ManyToManyChannel.put_BANG_(channels.clj:150)
    at clojure.core.async.impl.ioc_macros$put_BANG_.invoke(ioc_macros.clj:959)
    at typedclj.async$eval11807$fn__11816$state_machine__6185__auto____11817$fn__11819.invoke(async.clj:19)
    at typedclj.async$eval11807$fn__11816$state_machine__6185__auto____11817.invoke(async.clj:19)
    at clojure.core.async.impl.ioc_macros$run_state_machine.invoke(ioc_macros.clj:940)
    at clojure.core.async.impl.ioc_macros$run_state_machine_wrapped.invoke(ioc_macros.clj:944)
    at typedclj.async$eval11807$fn__11816.invoke(async.clj:19)
    at clojure.lang.AFn.run(AFn.java:22)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)...

根据http://martintrojer.github.io/clojure/2013/07/07/coreasync-and-blocking-io/

  

...这将打破1个作业= 1个线程结,从而这个线程   停车将使我们能够扩大任何工作的数量   平台上的线程限制(通常在JVM上大约1000)。

     

core.async提供(阻塞)通道和新的(无界)线程池   当使用&#39;线程&#39;。这(实际上)只是使用了一些糖   java线程(或clojure期货)和BlockingQueues来自   java.util.concurrent中。主要特征是去线程中的线程   可以停止并恢复(可能)阻止呼叫处理   使用core.async的频道......

1e4工作已经太多了吗?那么上限是多少?

2 个答案:

答案 0 :(得分:4)

我通常不会这样咆哮,所以我希望你能原谅我这一次违规行为:

在一个更加完美的世界里,每个程序员都会在睡觉前五次重复自己“没有无界排队”这样的事情。这种思维模式需要确定如何在系统中处理背压,因此当流程中的某个地方出现减速时,之前的部件有办法找到它并减慢自身的响应速度。 在core.async中,默认背压是立即,因为默认缓冲区大小为零。没有阻止成功将某些东西放入陈中,直到有人准备好消费它。

chans看起来基本上是这样的:

"queue of pending puts" --> buffer --> "queue of pending takes"

推杆和接受者队列旨在为通过此管道进行通信的两个进程留出时间来安排自己,以便可以取得进展。没有这些,线程就没有空间来安排,并且会发生死锁。它们 NOT 旨在将用作缓冲区。多数民众赞成在中间的缓冲区是什么,这是设计背后的唯一具有明确大小的设计。 通过设置chan中缓冲区的大小,显式设置 系统的缓冲区大小:

user> (time (dorun
        (let [c (chan 1e6)]
          (doseq [i (range 10 1e4)]
            (go (>! c i))))))
"Elapsed time: 83.526679 msecs"
nil

在这种情况下,我已“计算”如果有多达一百万个等待工作,我的整个系统将处于良好状态。当然,你的真实世界将会有所不同,而且非常独特。

感谢您的耐心等,

答案 1 :(得分:2)

未消耗的放置限制是通道缓冲区的大小加上队列的大小。

core.async中的队列大小限制为1024,但不应该依赖于此。