3

コードでメモリ不足の例外が発生する理由がわかりません。

「test.log」ファイルに行を追加する関数を呼び出すエージェントがあります。メモリ不足がオンになっていPersistentHashMap $ BitmapIndexedNode.assoc(PersistentHashMap.java:624)ます。

(use 'clojure.java.io)

(def the-agent(agent nil))

(defn process [_o content]

    (spit "test.log" content :append true)

)

(defn write-all []

    (doseq
        [x (range 1 5000000)]
        (send-off
            the-agent
            process
            "Line to be appended\n"
        )
    )

)

ありがとう !

4

2 に答える 2

4

多くのエージェントが同時にブロッキング (または単に長い) タスクを実行している場合、Clojure のデフォルトの動作で問題が発生する可能性があります。デフォルトでは、このような状況で失敗する傾向がある無制限の並列処理send-offを使用します。幸いなことに、Clojure 1.5 に加えて、送信によって使用される実行戦略を設定して、並列実行の程度を制限できます。

(use 'clojure.java.io)
(def the-agent (agent nil))
(defn process [_o content]
  (spit "test.log" content :append true))

(set-agent-send-executor!
  (java.util.concurrent.Executors/newFixedThreadPool 20))

(defn write-all []
  (doseq
      [x (range 1 5000000)]
    (send-off
     the-agent
     process
     "Line to be appended\n")))

その後、メモリが不足することなく完了します。

hello.core> (write-all)
nil
hello.core> 

これは、ほとんどの場合、すべてのエージェントに影響するグローバルな変更send-viaです。このタスク専用のスレッド プールを作成し、その特定のプールを使用するために使用することをお勧めします。

(def output-thread-pool (java.util.concurrent.Executors/newFixedThreadPool 20))
(defn write-all []
  (doseq 
      [x (range 1 5000000)]
    (send-via output-thread-pool
     the-agent
     process
     "Line to be appended\n"))) 

これにより、各タスクに必要な並列処理の度合いを選択できます。終了したら、スレッド プールをシャットダウンすることを忘れないでください。

于 2013-08-07T21:26:13.660 に答える
3

ディスパッチされた送信は、個々のスピットの I/O でブロックされます。ディスパッチは、完了して蓄積するよりもはるかに速く作成されます。

(defn write-all [] 
  (doseq [x (range 1 5000000)] 
    (send-off the-agent process "foo") 
    (when (zero? (mod x 100000)) 
  (println (. the-agent clojure.lang.Agent/getQueueCount)))))


user=> (write-all)
99577
199161
298644
398145
497576
596548
Exception in thread "nREPL-worker-0" java.lang.OutOfMemoryError: Java heap space
于 2013-08-07T13:45:49.600 に答える