我想在Clojure中创建一些未来,并在一个特定的线程上运行它们,以确保它们一次运行一个。这可能吗?
包装Java库来实现这一点并不难,但在此之前,我希望确保不会遗漏Clojure的实现方式。在Java语言中,我可以通过实现FutureTask并将这些任务提交给单线程执行器来实现这一点。
发布于 2017-12-28 04:56:44
Clojure的future macro调用使用a dedicated executor service的future-call函数。这意味着您无法控制执行顺序执行。
另一方面,您可以使用promise而不是future对象和一个future线程来顺序地deliver结果。Promise的API与future提供的API类似。他们也有deref和realized?。
下面的代码示例在后台的新线程上顺序执行子任务,而函数的直接返回结果包含对计算值的承诺。
(defn start-async-calc []
(let [f1 (promise)
f2 (promise)
f3 (promise)]
(future
(deliver f1 (task-1))
(deliver f2 (task-2))
(deliver f3 (task-3)))
{:task1 f1
:task2 f2
:task3 f3}))发布于 2017-12-28 05:32:37
如果您想对future调用进行序列化,您可以手动使用它,如下所示:
(do @(future 1)
@(future 2)
@(future 3))它们仍然可能在不同的线程中调用,但在前一个线程完成之前不会调用下一个线程。这是由@ (或deref函数)保证的。这意味着在其中执行do表单的线程将在完成之前被前一个promise阻塞,然后产生下一个线程。
你可以像下面这样使用宏来美化它:
(defmacro sequentialize [& futures]
`(do ~@(map #(list `deref %) futures)))
user> (let [a (atom 1)]
(sequentialize
(future (swap! a #(* 10 %)))
(future (swap! a #(+ 20 %)))
(future (swap! a #(- %))))
@a)
;;=> -30这与手动do的作用完全相同。请注意,a原子的突变是有序的,即使某些线程运行的时间更长:
user> (let [a (atom 1)]
(sequentialize
(future (Thread/sleep 100)
(swap! a #(* 10 %)))
(future (Thread/sleep 200)
(swap! a #(+ 20 %)))
(future (swap! a #(- %))))
@a)
;;=> -30发布于 2017-12-28 17:49:50
Manifold提供了一种创建未来with specific executor的方法。它不是核心Clojure库的一部分,但它仍然是一个高质量的库,并且可能是一个最佳选择,以防您需要比核心库提供更多的灵活性来处理未来(而不是求助于Java互操作)。
https://stackoverflow.com/questions/47998199
复制相似问题