比方说,我这样做:未来总是会创建一个新的线程吗?
(future
(do-the-thing))
我保证,无论什么(do-the-thing)
呢,
- 一个全新的线程将被创建,而不是让一个从池中或类似的东西那?
- 没有什么比
(do-the-thing)
永远运行在新的线程? - 一旦
(do-the-thing)
在该新线程上执行,线程将终止?
如果不是,那么在什么情况下这些假设是错误的?
比方说,我这样做:未来总是会创建一个新的线程吗?
(future
(do-the-thing))
我保证,无论什么(do-the-thing)
呢,
(do-the-thing)
永远运行在新的线程?(do-the-thing)
在该新线程上执行,线程将终止?如果不是,那么在什么情况下这些假设是错误的?
简短的回答是没有
从Clojure的core.clj:
(defmacro future
...
[& body] `(future-call (^{:once true} fn* [] [email protected])))
...
(defn future-call
...
[f]
(let [f (binding-conveyor-fn f)
fut (.submit clojure.lang.Agent/soloExecutor ^Callable f)]
...
所以未来的执行者是clojure.lang.Agent/soloExecutor
。
volatile public static ExecutorService soloExecutor = Executors.newCachedThreadPool(
createThreadFactory("clojure-agent-send-off-pool-%d", sendOffThreadPoolCounter));
你可以看到,soloExecutor
由Executors.newCachedThreadPool()
创建从document of Executors.newCachedThreadPool:
创建一个可根据需要创建新线程的线程池,但会重用先前构建的线程在可用时。这些池通常会提高执行许多短暂异步任务的程序的性能。调用执行将重用以前构造的线程(如果可用)。如果没有现有线程可用,则会创建一个新线程并将其添加到池中。未使用六十秒的线程将被终止并从缓存中移除。因此,保持闲置时间足够长的池不会消耗任何资源。请注意,使用ThreadPoolExecutor构造函数可以创建具有类似属性但具有不同细节的池(例如,超时参数)。
所以答案是(do-the-thing)
的一些其他工作可以在同一个线程中执行,如果没有更多的工作,线程将在60秒后终止。
您可以确认的Executors.newCachedThreadPool
行为在下面的代码:
(doseq [i (for [x (range 10)] (future (Thread/sleep 1000) (.getId (Thread/currentThread))))] (print @i) (print " "))
执行Clojure中的控制台这段代码,你会得到:
50 49 48 47 46 45 44 43 42 41 nil
首次。并且在5秒后再次执行它,您将获得:
50 49 43 41 45 42 46 47 48 44 nil
因此您可以确认线程是否被重用。
如果执行相同的代码60秒后,您将获得:
60 59 58 57 56 55 54 53 52 51 nil
所以,你可以确认以前的线程终止运营,创造了新的线程。
为了以防人们感兴趣:'core.async'使用'newFixedThreadPool':http://stackoverflow.com/questions/949355/java-newcachedthreadpool-versus-newfixedthreadpool – ClojureMostly
我的理解是,Clojure的未来不使用专业化图书馆的期货只不过是Java期货。所以这可能已经被问及作为Java问题回答。 –
@ChrisMurphy如果您可以将我链接到Java问题,那将非常棒! –
Java期货板块,而斯卡拉的没有。然而,Clojure的这个缺点已经被这个[library]修复了(https://github.com/leonardoborges/imminent)。 –