Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.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
Multithreading Clojure-高效并发地增加列表中的数字_Multithreading_Performance_Data Structures_Concurrency_Clojure - Fatal编程技术网

Multithreading Clojure-高效并发地增加列表中的数字

Multithreading Clojure-高效并发地增加列表中的数字,multithreading,performance,data-structures,concurrency,clojure,Multithreading,Performance,Data Structures,Concurrency,Clojure,简短版本:在Clojure中存储数百个数字的列表的正确方法是什么,其中每个数字都会增加数百万倍(可能跨越多个线程) 长版本:程序以空向量开始,其中每个值初始化为0: [0 0 0 0 0 0 0 0 0 ...] 然后逐行读取数百万行文件。在一行上执行一些任意计算后,程序会增加向量中的一些值。在第一行之后,向量可能如下所示: [1 1 1 2 0 1 0 1 1 ...] 第二行之后: [2 2 3 2 2 1 0 2 2 ...] 大约5000行之后,它可能看起来像: [5000 499

简短版本:在Clojure中存储数百个数字的列表的正确方法是什么,其中每个数字都会增加数百万倍(可能跨越多个线程)

长版本:程序以空向量开始,其中每个值初始化为0:

[0 0 0 0 0 0 0 0 0 ...]
然后逐行读取数百万行文件。在一行上执行一些任意计算后,程序会增加向量中的一些值。在第一行之后,向量可能如下所示:

[1 1 1 2 0 1 0 1 1 ...]
第二行之后:

[2 2 3 2 2 1 0 2 2 ...]
大约5000行之后,它可能看起来像:

[5000 4998 5008 5002 4225 5098 5002 5043 ...]
因为Clojure的数据结构是不可变的,仅仅使用
assoc
来增加向量中的值似乎是非常浪费的,因为每个增量都会复制整个向量

在不花费所有CPU时间复制不变的数据结构的情况下,进行这种并发数据聚合的正确方法是什么?我是否应该有一个向量,其中每个元素类似于ref或atom,所有线程都递增这些共享值?或者,是否有某种线程级数据结构可以存储计数,然后最后一步是合并每个线程的计数


这可能不会在单个线程上绑定I/O,所以我猜我将在多个线程上拆分行处理。向量的长度没有限制(可能有几千个元素长),但很可能大约有100个元素长。

Clojure的
vector
是持久数据结构。当在向量中更新一个元素时,它不会复制整个元素,并且需要基本上恒定的时间,这意味着O(log32n)


但似乎每次迭代都在更新向量中的几乎每个元素。也许您想参考一下。

我想知道core.matrix是否有助于此目的。这有点过分,但会使更新更容易。如果您探索这条路线,我建议您尝试不同的实现(ndarray、vectorz和clatrix支持可变性),看看哪种实现最快。

一种方法是将向量创建为原子向量(而不是值),然后同时更新向量中的原子

(def len 1000)

(def vec-data (into [] (repeatedly len #(atom 0))))

;Create 10 future (threads) that update the vector atoms concurrently    
(doall (for [_ (range 10)]
            (future (doall (map #(swap! (vec-data %) inc) (range len) )))))

我建议如下:

  • 使用
    core.matrix
    API进行向量操作
  • 也许可以使用可变向量实现(假设双精度数字适合您?)
  • 使用
    (零向量n)
  • 每个线程将在一行上进行计算,生成一个新的向量添加到累加器中
  • 然后调用
    (add!acculator…
    对累加器向量执行可变加法(如果担心线程安全,可以使用代理或其他并发技术序列化这些加法)

哦,你确实同时说了,我在发帖之前一直没有听到。很抱歉在我的帖子中向下滚动,看看我建议如何同时做

(def len 1000)

(def vec-data (into [] (repeatedly len #(atom 0))))

;Create 10 future (threads) that update the vector atoms concurrently    
(doall (for [_ (range 10)]
            (future (doall (map #(swap! (vec-data %) inc) (range len) )))))
您可以在Clojure中使用java字节数组或长数组。你只需要小心地控制你如何使用它们

例如,这里有一个质数筛,它演示了两件事

首先,它使用字节数组,并使用aset字节设置数组中的字节,然后使用aget访问这些字节。请参阅第一个let语句,其中设置了[flags(字节数组大小)]。还可以使用(长数组大小)返回长数组。但是您应该使用(aset long array index value)在该长数组中设置值

第二,与您的问题没有直接关系,它使用一个瞬态向量(标准Clojure特性)在循环结束时建立结果,然后在返回持久向量之前将该向量转换为持久向量

(defn sieve1
  "Generate a vector of all prime numbers up to maxN.
   maxN must be 2 or greater."
  [maxN]

  (when (< maxN 2)
    (throw (java.lang.IllegalArgumentException. (str "parameter maxN (" maxN ") must be 2 or greater."))))

  (let [size (inc maxN) ; because array is zero based
        ;nSqrt (dbmath/isqrt maxN)
        flags (byte-array size)]
    ;(println (format "maxN: %s; size: %s; nSqrt: %s" maxN size, nSqrt))

    ; Set all flags.
    (loop [i 0]
        (when (<= i maxN)
          (aset-byte flags i 1)
          (recur (inc i))))

    ; Strike out all non primes before two.
    ; (zero and one are not prime.)
    (aset-byte flags 0 0)
    (aset-byte flags 1 0)

    ; Strike out multiples of 2.
    ;(println "strike out multiples of two.")
    (loop [j 4]
      (when (<= j maxN)
        ;(println (format "aset %s 0" j))
        (aset-byte flags j 0)
        (recur (+ j 2))))

    ; Strike out multiples of primes (only odd primes are now remaining)
    ;(println "strike out multiples of primes.")
    (loop [i 3]
      (when (<= i maxN)
        (when (= 1 (aget flags i))
          ; found that i is prime.
          ;(println (format "discovered i is prime: i=%s;" i))

          ; Strike out multiples of i, starting with i^2.
          (loop [j (* i i)]
            (when (<= j maxN)
              ;(println (format "aset %s 0" j))
              (aset-byte flags j 0)
              (recur (+ j i))))
          )
        (recur (+ i 2))))

    ; Build result.
    (let [primes (transient [2])]
      (loop [i 3]
        (when (<= i maxN)
          (when (= 1 (aget flags i))
            (conj! primes i))
          (recur (+ i 2))
          ))
      (persistent! primes))
    ))
(定义1)
生成一个包含所有素数的向量,直到maxN。
maxN必须为2或更大。“
[maxN]
(当(