gpt4 book ai didi

clojure pmap - 为什么我不使用所有核心?

转载 作者:行者123 更新时间:2023-12-02 15:35:13 24 4
gpt4 key购买 nike

我正在尝试使用 clojure pantomime 库从大量 tif 文档(以及其他文档)中提取/ocr 文本。

我的计划是使用 pmap 将映射应用于一系列输入数据(来自 postgres 数据库),然后使用 tika/tesseract OCR 输出更新同一 postgres 数据库。这一直工作正常,但是我注意到 htop 中许多核心有时处于空闲状态。

有没有办法解决这个问题,我可以采取什么步骤来确定为什么这可能会在某个地方阻塞?所有处理都发生在单个 tif 文件上,并且每个线程完全互斥。

其他信息:

  1. 一些 tika/tesseract 进程需要 3 秒,其他进程最多需要 90 秒。一般来说,tika 严重依赖 CPU。根据 htop,我有足够的可用内存。
  2. postgres 在 session 管理中没有锁定问题,所以我认为这不会阻碍我。
  3. 也许 future 的某个地方正在等待取消引用?怎么知道在哪里?

任何提示表示赞赏,谢谢。下面添加了代码。

(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 )
)

最佳答案

pmap 在(+ 2 个核心)批处理上并行运行映射函数,但保留顺序。这意味着如果您有 8 个核心,则将处理一批 10 个项目,但只有在所有 10 个项目都完成后才会开始新批处理。

您可以使用 futuredelayderef 的组合来创建自己的代码,这将是很好的学术练习。之后,您可以扔掉代码并开始使用 claypoole库,它有一组抽象,涵盖了 future 的大部分用途。

对于这种特定情况,请使用其无序 pmappfor 实现(upmapupfor),这做与 pmap 完全相同的事情,但没有顺序;当批处理中的任何一件元素完成后,就会立即拾取新元素。

在 IO 是主要瓶颈的情况下,或者工作项之间的处理时间差异很大的情况下,并行化 mapfor 操作是最好的方法。

当然,您应该注意不要依赖任何类型的返回值排序。

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

(cp/upmap (cp/ncpus)
#(try
(update-a-row %)
(catch Exception e (t/error (.getNextException e)))
)
fetch-all-batch )

关于clojure pmap - 为什么我不使用所有核心?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36828918/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com