与Clojure线程长运行过程和比较他们的回报 [英] with Clojure threading long running processes and comparing their returns

查看:94
本文介绍了与Clojure线程长运行过程和比较他们的回报的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对两个非常大的数据集需要处理两个不同的函数,最后得到两个布尔值。那些值需要然后一起被用于最终结果。我的问题是什么是最好的方式来创建线程,所以两个长函数可以同时运行。我的想法是像

 (def f(future longProcessOne(data_one)))
longProcessTwo(data_two)))
(和@f @g)

解决方案

(基于Promise的方法在顶部,核心。基于异步的方法向下移动。第一个假值的短路。)






使用单个promise可以多次传递(尽管只有第一个传递将成功设置其值;随后传递简单地返回 nil ,没有副作用)

 (defn thread-和
计算fs的返回值的逻辑结合,其中每个
将在未来被调用在第一个falsey值上短路(取消剩余的
期货)
[& fs]
(let [done(promise)
ret(atom true)
fps(promise)]
(deliver fps(doall(for [f fs]
(let [p(promise)]
[ $ b(if-not(swap!
(传递真)
(传递真)
(传递真实)
(传递真) (map peek @fps))
(deliver done true))))
p])))
@done
(doseq [[fut] @fps] $ b $一些测试: p>

 (线程和(不断地为真)(不断为真))
;; = true

(线程和(不断地为真)(不断为假))
;; = false

(重复100000
#和(不断为真)(不断为假))))
;; = true

;;打印:foo,但不是:bar
(线程和#(做线程/睡眠1000)(println:foo))
#(do(Thread / sleep 3000)(println:bar) )






将Arthur和A. Webb的想法放在一起,你可以使用core.async和结果,同时短路第一个falsey值返回:

 (defn thread-和
在一个单独的线程上调用每个fs。返回逻辑
结果连接短路(并取消调用
到剩余的fs)返回第一个falsey值。
[& fs]
(let [futs-and-cs
(doall(for [f fs]
(let [c(chan)]
[ (future(> !! c(f)))c]))]]
(loop [futs-and-cs futs-and-cs]
(if(seq futs-and-cs )
(let [[result c](alts !!(map peek futs-and-cs))]
(如果结果为
c)
futs-and-cs))
(do(doseq [fut(map first futs-and-cs)]
(future-cancel fut))
false) ))
true))))

使用测试false)(不断为真)

 <$ c $ 
; = true
(线程和(不断为真)(不断为真))
; = false

;;;等等。

还要注意,短路确实起作用:

  ;;;打印:foo返回之前
(线程和#(do(Thread / sleep 3000)false)
#(do(Thread / sleep 1000)(println:foo)))

;;;不打印:foo
(线程和#(做(线程/睡眠3000)假)
#(do(Thread / sleep 7000)(println:foo)))


I have two different function on two very large sets of data that need to be processed, in the end coming down to two Boolean values. those values need to then be anded together for the final result. my question is what is the best way to create threads so the two long functions can run at the same time. my thoughts were something like,

(def f (future longProcessOne(data_one)))
(def g (future longProcessTwo(data_two)))
(and @f @g)

but I was looking for input on a better way to go about this.

解决方案

(Promise-based approach at the top, core.async-based approach lower down. Both short-circuit on first falsey value.)


Here's a version making use of the fact that a single promise can be delivered multiple times (although only the first delivery will succeed in setting its value; subsequent deliveries simply return nil with no side effects).

(defn thread-and
  "Computes logical conjunction of return values of fs, each of which
  is called in a future. Short-circuits (cancelling the remaining
  futures) on first falsey value."
  [& fs]
  (let [done (promise)
        ret  (atom true)
        fps  (promise)]
    (deliver fps (doall (for [f fs]
                          (let [p (promise)]
                            [(future
                               (if-not (swap! ret #(and %1 %2) (f))
                                 (deliver done true))
                               (locking fps
                                 (deliver p true)
                                 (when (every? realized? (map peek @fps))
                                   (deliver done true))))
                             p]))))
    @done
    (doseq [[fut] @fps]
      (future-cancel fut))
    @ret))

Some tests:

(thread-and (constantly true) (constantly true))
;;= true

(thread-and (constantly true) (constantly false))
;;= false

(every? false?
        (repeatedly 100000
                    #(thread-and (constantly true) (constantly false))))
;;= true

;; prints :foo, but not :bar
(thread-and #(do (Thread/sleep 1000) (println :foo))
            #(do (Thread/sleep 3000) (println :bar)))


Putting Arthur's and A. Webb's ideas together, you could use core.async to and the results together while short-circuiting on the first falsey value returned:

(defn thread-and
  "Call each of the fs on a separate thread. Return logical
  conjunction of the results. Short-circuit (and cancel the calls
  to remaining fs) on first falsey value returned."
  [& fs]
  (let [futs-and-cs
        (doall (for [f fs]
                 (let [c (chan)]
                   [(future (>!! c (f))) c])))]
    (loop [futs-and-cs futs-and-cs]
      (if (seq futs-and-cs)
        (let [[result c] (alts!! (map peek futs-and-cs))]
          (if result
            (recur (remove #(identical? (peek %) c)
                           futs-and-cs))
            (do (doseq [fut (map first futs-and-cs)]
                  (future-cancel fut))
                false)))
        true))))

Test with (constantly false) and (constantly true):

(thread-and (constantly true) (constantly true))
;= true
(thread-and (constantly true) (constantly false))
;= false

;;; etc.

Also note that short-circuiting does indeed work:

;;; prints :foo before returning false
(thread-and #(do (Thread/sleep 3000) false)
            #(do (Thread/sleep 1000) (println :foo)))

;;; does not print :foo
(thread-and #(do (Thread/sleep 3000) false)
            #(do (Thread/sleep 7000) (println :foo)))

这篇关于与Clojure线程长运行过程和比较他们的回报的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆