Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Concurrency 如何列出并行的阻塞调用列表,并以先到先得的方式获得结果?_Concurrency_Clojure_Parallel Processing - Fatal编程技术网

Concurrency 如何列出并行的阻塞调用列表,并以先到先得的方式获得结果?

Concurrency 如何列出并行的阻塞调用列表,并以先到先得的方式获得结果?,concurrency,clojure,parallel-processing,Concurrency,Clojure,Parallel Processing,基本上我有一个要调用的函数列表 '(f1 f2 f3 f4) 每个都是阻塞的,需要不同的时间返回 我想要一个惰性序列s,其中第一个元素是返回调用最快的结果,调用 (first s) 将只阻塞该呼叫的响应时间。其他元素也是如此 具体例子:如果 f1需要10秒 f2需要5秒 f3需要1秒 f4需要2秒 然后打电话 (first s) 将阻塞1s并返回(f3)的结果 将阻塞2s并返回(f3)和(f4)等的结果 我曾考虑将所有功能包装在futures中,并将结果交付给promises。 但我不

基本上我有一个要调用的函数列表

'(f1 f2 f3 f4)
每个都是阻塞的,需要不同的时间返回

我想要一个惰性序列s,其中第一个元素是返回调用最快的结果,调用

(first s)
将只阻塞该呼叫的响应时间。其他元素也是如此

具体例子:如果

  • f1需要10秒
  • f2需要5秒
  • f3需要1秒
  • f4需要2秒
然后打电话

(first s)
将阻塞1s并返回(f3)的结果

将阻塞2s并返回(f3)和(f4)等的结果

我曾考虑将所有功能包装在futures中,并将结果交付给promises。 但我不知道如何确定哪一个承诺会最快兑现

有人知道怎么做吗?

(需要“[clojure.core.async
(require '[clojure.core.async
           :refer [chan
                   >!
                   go
                   <!!]])

(def c (chan))

(def fns [#(do (Thread/sleep 5000) :fn-1)
          #(do (Thread/sleep 2000) :fn-2)
          #(do (Thread/sleep 1000) :fn-3)])
(do
  (go
    (doseq [f fns]
      (go (>! c (f)))))

  (println "First => " (<!! c)))
:参阅[陈 >! 去 !c(f)(()))
(println“First=>”(如果不想使用core.async,可以回退到一个简单队列:

(import 'java.util.concurrent.LinkedBlockingQueue)

(defn fut [q f] ;; this will need some error handling
  (future
    (.add q (f))))

(defn take-blocking [q n]
  (when (pos? n)
    (lazy-seq
     (cons (.take q)
           (take-blocking q (dec n))))))

(defn in-parallel [fns]
  (let [queue (LinkedBlockingQueue. (count fns))]
    (doseq [f fns]
      (fut queue f))
    (take-blocking queue (count fns))))
要使用它:

(defn slow [n]
  (fn []
    (Thread/sleep (* n 1000))
    n))

(doseq [r (in-parallel [(slow 5) (slow 9) (slow 1) (slow 3)])]
  (println (java.util.Date.) r))

使用承诺、未来和单个原子的纯Clojure解决方案绝对是可能的:

(defn parallelize
  [fs]
  (let [[h & r :as ps] (repeatedly (count fs) promise)
        queue (atom (cycle ps))]
    (doseq [f fs]
      (future
        (let [result (f)]
          (-> (swap! queue rest)
              (first)
              (deliver result)))))
    (map deref (concat r [h]))))
这基本上创建了一系列承诺,并使用一个原子将它们存储为一个循环队列。然后,每个future循环队列,选择下一个可用承诺并交付函数结果

例如:

(defn g
  [ms]
  (fn []
    (Thread/sleep ms)
    ms))

(doseq [value (parallelize (map g [500 200 100 300]))]
  (prn value))
;; 100
;; 200
;; 300
;; 500

简单并发和控制工作线程的另一个很好的选择是。它模仿
map
for
,但并行,有序或无序,并控制线程池大小(与pmap不同,pmap的线程池大小固定在(*2个核心))

下面是upmap的一个示例,upmap是其无序并行版本的map。这意味着首先返回映射序列的最快实现版本。第一个参数是预定义的线程池或要使用的线程池的大小

(require '[com.climate.claypoole :as cp]))

(defn wait-and-return
  [w]
  (Thread/sleep (* 1000 w))
  w)

(cp/upmap 4 wait-and-return [10 5 7 9])
=> (5 7 9 10)
确保线程池的大小足够大,以容纳最大数量的并行等待/io绑定函数

(def to-sort
  (shuffle (range 0 40 2))

;not enough threads, so not returned in the right order
(def timesorted
  (time (doall (cp/upmap 10 wait-and-return to-sort))))
"Elapsed time: 52001. 812056 msecs"

(apply < timesorted)
=> false

;enough threads
(def timesorted
  (time (doall (cp/upmap 20 wait-and-return to-sort))))
"Elapsed time: 38002.858901 msecs"

(apply < timesorted)
=> true
(要排序的定义)
(洗牌(范围0 40 2))
;线程不足,因此未按正确顺序返回
(def timesorted)
(时间(doall(cp/upmap 10等待并返回排序)))
“运行时间:52001.812056毫秒”
(应用<时间排序)
=>错误
;足够的线程
(def timesorted)
(时间(doall(cp/upmap 20等待并返回排序)))
“运行时间:38002.858901毫秒”
(应用<时间排序)
=>正确
Futures不会遇到这些情况,因为它们的线程池会自动增加到整数/MAX_值的最大值。但是,如果您指定的不是claypoole线程池或线程池大小,而是:builtin键,claypoole将使用Clojure自己的几乎无限的线程池,用于Futures和代理发送

但是,请注意,如果您不知道线程数量会增长到什么程度,那么管理和切换所有这些线程可能会导致性能降低,因此您应该仅在IO限制的情况下使用它,而不是在CPU限制的情况下

(def timesorted
  (time (doall (cp/upmap :builtin wait-and-return to-sort))))
"Elapsed time: 38001.348402 msecs"

(apply < timesorted)
=> true
(def timesorted
(时间(doall(cp/upmap:内置等待并返回排序)))
“运行时间:38001.348402毫秒”
(应用<时间排序)
=>正确

你能说得更具体一点吗?core.async中的fns/宏在对其余部分进行计算之前是否已加载到命名空间中?另外,你知道
的阻塞是否正确吗?你可以使用
take!
(转到(我不熟悉core.async,是否没有办法使用通常的clojure并发结构来实现它?将查看是否有第二个答案。可能是
代理
发送
(def timesorted
  (time (doall (cp/upmap :builtin wait-and-return to-sort))))
"Elapsed time: 38001.348402 msecs"

(apply < timesorted)
=> true