clojure pmap - why aren't i using all the cores?
我正在尝试使用clojure
我的计划是使用pmap将映射应用于一系列输入数据(来自postgres数据库),然后使用tika / tesseract OCR输出更新相同的postgres数据库。这一直很好,但是我在htop中注意到许多内核有时处于空闲状态。
无论如何,有没有调和的方法,我可以采取哪些步骤来确定为什么它可能会阻塞某处?所有处理都在单个tif文件中进行,并且每个线程是完全互斥的。
附加信息:
任何提示表示赞赏,谢谢。下面添加了代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | (defn parse-a-path [{:keys [row_id, file_path]}] (try (let [ start (System/currentTimeMillis) mime_type (pm/mime-type-of file_path) file_content (-> file_path (extract/parse) :text) language (pl/detect-language file_content) ] {:mime_type mime_type :file_content file_content :language language :row_id row_id :parse_time_in_seconds (float (/ ( - (System/currentTimeMillis) start) 100)) :record_status"doc parsed"}))) (defn fetch-all-batch [] (t/info (str"Fetching lazy seq. all rows for batch.") ) (jdbc/query (db-connection) ["select row_id, file_path , file_extension from the_table" ])) (defn update-a-row [{:keys [row_id, file_path, file_extension] :as all-keys}] (let [parse-out (parse-a-path all-keys )] (try (doall (jdbc/execute! (db-connection) ["update the_table set record_last_updated = current_timestamp , file_content = ? , mime_type = ? , language = ? , parse_time_in_seconds = ? , record_status = ? where row_id = ?" (:file_content parse-out) , (:mime_type parse-out) , (:language parse-out) , (:parse_time_in_seconds parse-out) , (:record_status parse-out) , row_id ]) (t/debug (str"updated row_id" (:row_id parse-out)" (" file_extension")" " in" (:parse_time_in_seconds parse-out)" seconds." ))) (catch Exception _ )))) (dorun (pmap #(try (update-a-row %) (catch Exception e (t/error (.getNextException e))) ) fetch-all-batch ) ) |
您可以使用
对于这种特定情况,请使用其无序的
在IO是主要瓶颈的情况下,或者在各个工作项之间处理时间可能相差很大的情况下,这是并行化
当然,您应该注意不要依赖于返回值的任何排序。
1 2 3 4 5 6 7 8 | (require '[com.climate.claypoole :as cp]) (cp/upmap (cp/ncpus) #(try (update-a-row %) (catch Exception e (t/error (.getNextException e))) ) fetch-all-batch ) |
我前段时间也遇到过类似的问题。我猜您在做与我相同的假设:
-
pmap并行调用f。但这并不意味着作品将被平均分配。如您所说,有些需要3秒钟,而有些则需要90秒钟。 3秒内完成的线程不会要求其他线程共享剩下要做的一些工作。因此,完成的线程只需等待中线,直到最后一个完成。
-
您没有确切描述数据的方式,但是我假设您使用的是某种惰性序列,这对并行处理不利。如果您的进程受CPU限制,并且您可以将整个输入保存在内存中,则首选使用clojure.core.reducers(" map"," filter"和特别是" fold"),而不是使用惰性映射,filter和其他。
以我为例,这些技巧将处理时间从34秒减少到仅8秒。希望能帮助到你