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 plus中,您可以设置 send-off 使用的执行策略来限制并行执行的程度

(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 回答