我有两个独立的昂贵的函数。我想让它们并行运行。我不想和期货之类的东西打交道(我是Clojure的新手,很容易混淆)。
我正在寻找一种简单的方法来同时运行两个函数。我希望它像下面这样工作
(defn fn1 [input] ...) ; costly
(defn fn2 [input] ...) ; costly
(let [[out1 out2] (conc (fn1 x) (fn2 y))] ...)我想让它返回一个带有一对输出的向量。它应该只在两个线程都终止后才会返回。理想情况下,conc应该适用于任意数量的输入。我怀疑这是一个简单的模式。
发布于 2012-09-14 08:10:13
您确实需要一个宏来保留所需的语法,尽管如其他答案所示,还有其他方法可以获得相同的行为。这里有一种方法:
(defn f1 [x] (Thread/sleep 500) 5)
(defn f2 [y] 2)
(defmacro conc [& exprs]
`(map deref
[~@(for [x# exprs] `(future ~x#))]))
(time (let [[a b] (conc (f1 6) (f2 7))]
[a b]))
; "Elapsed time: 500.951 msecs"
;= (5 2)扩展显示了它是如何工作的:
(macroexpand-1 '(conc (f1 6) (f2 7)))
;= (clojure.core/map clojure.core/deref [(clojure.core/future (f1 6))
;= (clojure.core/future (f2 7))])您指定了两个函数,但这应该适用于任意数量的表达式。
发布于 2012-09-14 06:48:04
在Clojure中使用期货非常容易。无论如何,这里有一个避免它们的答案。
(defn conc [& fns]
(doall (pmap (fn [f] (f)) fns)))pmap在幕后使用期货。doall将强制序列求值。
(let [[out1 out2] (conc fn1 fn2)]
[out1 out2])请注意,我解构了out1和out2,试图保留您的示例。
发布于 2012-09-14 06:49:23
我知道你不希望你的最终解决方案暴露期货,尽管它有助于说明如何使用期货来做到这一点,然后将它们包装在隐藏此细节的东西中:
core> (defn fn1 [input] (java.lang.Thread/sleep 2000) (inc input))
#'core/fn1
core> (defn fn2 [input] (java.lang.Thread/sleep 3000) (* 2 input))
#'core/fn2
core> (time (let [f1 (future (fn1 4)) f2 (future (fn2 4))] @f1 @f2))
"Elapsed time: 3000.791021 msecs" 然后,我们可以将其封装在期货的许多clojure包装器中。最简单的是一个函数,它接受两个函数并并行运行它们。
core> (defn conc [fn1 fn2]
(let [f1 (future (fn1))
f2 (future (fn2))] [@f1 @f2]))
#'core/conc
core> (time (conc #(fn1 4) #(fn2 4)))
"Elapsed time: 3001.197634 msecs" 这避免了将其编写为宏的需要,因为conc接受要运行的函数而不是要计算的主体,然后通过将#放在调用的前面来创建要传递给它的函数。
这也可以用map和future-call来编写:
core> (map deref (map future-call [#(fn1 4) #(fn2 42)]))
(5 84) 然后,您可以即兴使用conc,直到它类似于(正如Julien Chastang明智地指出) pmap
https://stackoverflow.com/questions/12415316
复制相似问题