在对期货进行测试时,我发现:
user=> (time (doall (map deref (for [i (range 1000)]
#_=> (future (Thread/sleep 1000))))))
"Elapsed time: 32058.208 msecs"
当看到 2 的幂时,我的脑海中就会响起警钟。这闻起来好像只启动了 32 个线程。
一些有针对性的实验:
user=> (time (doall (map deref (for [i (range 32)]
#_=> (future (Thread/sleep 1000))))))
"Elapsed time: 1002.302 msecs"
(nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)
user=> (time (doall (map deref (for [i (range 64)]
#_=> (future (Thread/sleep 1000))))))
"Elapsed time: 2004.24 msecs"
(nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)
user=> (time (doall (map deref (for [i (range 65)]
#_=> (future (Thread/sleep 1000))))))
"Elapsed time: 3005.279 msecs"
(nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)
确认这一点。对于 32 个未来任务的每个切片,我们会看到额外的一秒。
创造未来的代码是
(defmacro future
"Takes a body of expressions and yields a future object that will
invoke the body in another thread, and will cache the result and
return it on all subsequent calls to deref/@. If the computation has
not yet finished, calls to deref/@ will block, unless the variant of
deref with timeout is used. See also - realized?."
{:added "1.1"}
[& body] `(future-call (^{:once true} fn* [] ~@body)))
未来通话中有趣的一点是
fut (.submit clojure.lang.Agent/soloExecutor ^Callable f)]
翻译为:
volatile public static ExecutorService soloExecutor = Executors.newCachedThreadPool(
createThreadFactory("clojure-agent-send-off-pool-%d", sendOffThreadPoolCounter));
所以这确实创建了一个无界的线程池。
那么为什么只运行 32 个线程而不是创建 1000 个线程并在一秒钟内返回呢?