使用pool.apply_async创建新线程的Windows 10上的Python 3.6多处理在多次迭代后停止工作

时间:2017-07-19 10:02:44

标签: windows multithreading python-multiprocessing

我最近开始使用pythons多处理库,并决定使用Pool()和apply_async()方法最适合我的问题。代码很长,但对于这个问题,我压缩了与函数中多处理无关的所有内容。

背景资料

基本上,我的程序应该采用一些数据结构并将其发送到另一个程序,该程序将处理它并将结果写入txt文件。我有几千个这样的结构(N * M),并且有大块(M)是独立的并且可以按任何顺序处理。我创建了一个工作池来处理这些M结构,然后再检索下一个块。为了处理一个结构,必须为外部程序创建一个新线程来运行。在处理过程中在外部程序之外花费的时间少于20%,因此如果我检查任务管理器,我可以看到外部程序在进程下运行。

实际问题

这种情况很有效,但经过多次处理后的结构(5000到20000之间的任何数字)突然外部程序停止显示在任务管理器中并且python子项运行在各自的峰值性能(~13%cpu) )没有产生任何更多的结果。我不明白问题可能是什么。剩下大量的RAM,每个孩子只使用大约90 Mb。也很奇怪,它工作了很长时间然后停止。如果我使用ctrl-c,它会在几分钟后停止,所以它对用户输入是半反应的。

我有一个想法是,当超时的外部程序线程被杀死(这种情况偶尔发生)时,可能没有正确关闭某些东西,以便子进程正在等待它找不到的东西?如果是这样,有没有更好的方法来处理超时的外部流程?

from multiprocessing import Pool, TimeoutError

N = 500         # Number of chunks of data that can be multiprocessed
M = 80          # Independed chunk of data
timeout = 100   # Higher than any of the value for dataStructures.timeout

if __name__ == "__main__":
    results = [None]*M
    savedData = []

    with Pool(processes=4) as pool:
        for iteration in range(N):
            dataStructures = [generate_data_structure(i) for i in range(M)]

            #---Process data structures---
            for iS, dataStructure in enumerate(dataStructures):
                results[iS] = pool.apply_async(processing_func,(dataStructure,))

            #---Extract processed data---
            for iR, result in enumerate(results):
                try:
                    processedData = result.get(timeout=timeout)
                except TimeoutError:
                    print("Got TimeoutError.")

                if processedData.someBool:
                    savedData.append(processedData)

这里也是为外部程序创建新线程的函数。

import subprocess as sp
import win32api as wa
import threading

def processing_func(dataStructure):
    # Call another program that processes the data, and wait until it is finished/timed out
    timedOut = RunCmd(dataStructure.command).start_process(dataStructure.timeout)

    # Read the data from the other program, stored in a text file
    if not timedOut:
        processedData = extract_data_from_finished_thread()
    else:
        processedData = 0.
    return processedData


class RunCmd(threading.Thread):
    CREATE_NO_WINDOW = 0x08000000

    def __init__(self, cmd):
        threading.Thread.__init__(self)
        self.cmd = cmd
        self.p = None

    def run(self):
        self.p = sp.Popen(self.cmd, creationflags=self.CREATE_NO_WINDOW)
        self.p.wait()

    def start_process(self, timeout):
        self.start()
        self.join(timeout)
        timedOut = self.is_alive()

        # Kills the thread if timeout limit is reached
        if timedOut:
            wa.TerminateProcess(self.p._handle,-1)
            self.join()
        return timedOut

0 个答案:

没有答案