簡體   English   中英

multiprocessing.Pool:如何在舊進程完成時啟動新進程?

[英]multiprocessing.Pool: How to start new processes as old ones finish?

我正在使用多處理池來管理 tesseract 進程(縮微膠片的 OCR 頁面)。 通常在一個包含 20 個 tesseract 進程的池中,幾頁將更難以 OCR,因此這些進程比其他進程花費的時間要長得多。 與此同時,池只是掛起,大多數 CPU 沒有被利用。 我希望讓這些落后者繼續下去,但我也想啟動更多進程來填滿現在閑置的許多其他 CPU,而這幾個粘性頁面正在完成。 我的問題:有沒有辦法加載新進程來利用這些空閑的 CPU。 換句話說,可以在等待整個池完成之前填充池中的空位嗎?

我可以使用 starmap 的異步版本,然后在當前池下降到一定數量的活動進程時加載一個新池。 但這似乎不優雅。 根據需要自動保持進程中的插槽會更優雅。

這是我的代碼現在的樣子:

def getMpBatchMap(fileList, commandTemplate, concurrentProcesses):
    mpBatchMap = []
    for i in range(concurrentProcesses):
        fileName = fileList.readline()
        if fileName:
            mpBatchMap.append((fileName, commandTemplate))
    return mpBatchMap

def executeSystemProcesses(objFileName, commandTemplate):
    objFileName = objFileName.strip()
    logging.debug(objFileName)
    objDirName = os.path.dirname(objFileName)
    command = commandTemplate.substitute(objFileName=objFileName, objDirName=objDirName)
    logging.debug(command)
    subprocess.call(command, shell=True)

def process(FILE_LIST_FILENAME, commandTemplateString, concurrentProcesses=3):
    """Go through the list of files and run the provided command against them,
    one at a time. Template string maps the terms $objFileName and $objDirName.

    Example:
    >>> runBatchProcess('convert -scale 256 "$objFileName" "$objDirName/TN.jpg"')
    """
    commandTemplate = Template(commandTemplateString)
    with open(FILE_LIST_FILENAME) as fileList:
        while 1:
            # Get a batch of x files to process
            mpBatchMap = getMpBatchMap(fileList, commandTemplate, concurrentProcesses)
            # Process them
            logging.debug('Starting MP batch of %i' % len(mpBatchMap))
            if mpBatchMap:
                with Pool(concurrentProcesses) as p:
                    poolResult = p.starmap(executeSystemProcesses, mpBatchMap)
                    logging.debug('Pool result: %s' % str(poolResult))
            else:
                break

你在這里混合了一些東西。 該池始終保持許多指定的進程處於活動狀態。 只要您不關閉池,無論是手動還是通過離開上下文管理器的 with 塊,您都不需要用進程重新填充池,因為它們不會去任何地方。

您可能想說的是“任務”,這些流程可以處理的任務。 任務是傳遞給池方法的可迭代對象的每個進程塊。 是的,在處理所有先前排隊的任務之前,有一種方法可以將池中的空閑進程用於新任務。 您已經為此選擇了正確的工具,池方法的異步版本。 您所要做的就是重新應用某種異步池方法。

from multiprocessing import Pool
import os

def busy_foo(x):
    x = int(x)
    for _ in range(x):
        x - 1
    print(os.getpid(), ' returning: ', x)
    return x

if __name__ == '__main__':

    arguments1 = zip([222e6, 22e6] * 2)
    arguments2 = zip([111e6, 11e6] * 2)

    with Pool(4) as pool:

        results = pool.starmap_async(busy_foo, arguments1)
        results2 = pool.starmap_async(busy_foo, arguments2)

        print(results.get())
        print(results2.get())

示例輸出:

3182  returning:  22000000
3185  returning:  22000000
3185  returning:  11000000
3182  returning:  111000000
3182  returning:  11000000
3185  returning:  111000000
3181  returning:  222000000
3184  returning:  222000000
[222000000, 22000000, 222000000, 22000000]
[111000000, 11000000, 111000000, 11000000]

Process finished with exit code 0

上面注意,以更簡單的任務結束的進程 3182 和 3185 會立即從第二個參數列表中的任務開始,而不需要先等待 3181 和 3184 完成。

如果出於某種原因,您真的想在每個進程處理了一定數量的任務后使用新進程,則可以使用Poolmaxtasksperchild參數。 在那里您可以指定池應該用新進程替換舊進程的任務數。 此參數的默認值是None ,因此默認情況下 Pool 不會替換進程。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM