我最近开始使用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