所以我编写了一个收集目录中文件列表的函数。将它们切成4的大小并使用for循环馈送到多进程池。以下是clairity的代码。
def Main():
allft_files = listdir(path_allft)
ncores = cpu_count()
start = datetime.datetime.now()
for i in range(0, len(allft_files ), ncores):
chuncks = [allft_files[x:x + 1] for x in range(i, i+4, 1)]
pool_processes = Pool(processes=ncores)
pool_processes.map(filter_allft, chuncks)
我的问题是,在下一次迭代开始之前是否所有进程都已完成并加入。或者,当其中一个进程完成时,脚本会跳转到for循环中的下一个迭代。因为每个过程的处理时间略有不同。我不确定游泳池在这方面是如何运作的。
答案 0 :(得分:1)
multiprocessing
文档让我发疯。池工作并返回结果。 map
函数会扇出一系列任务并等待所有任务完成,以便它可以汇编并返回所有结果。您认为文档会提到这一点!因此,正如您所怀疑的那样,map
必须在开始下一个数据集之前完全完成。
您的代码有一个错误 - 您在每次迭代中设置了一个新池,它只是放弃了旧池并且不必要地昂贵。至少,将池创建移出for
。
听起来您可以从使用其中一个异步调用中受益。 map
或apply
调用会立即返回一个ApplyResult
对象,您可以使用该对象等待结果。以下是关于您是否关心结果的几个例子。
import multiprocessing as mp
import time
import random
import contextlib
def worker(i,j):
time.sleep(random.random())
print('done', i, j)
if __name__ == "__main__":
# The Pool context manager terminates the pool (killing workers)
# but we just want to close (letting workers finish) and join.
with contextlib.closing(mp.Pool(8)) as pool:
for i in range(5):
for j in range(20):
pool.apply_async(worker, args=(i,j))
pool.join()
print("\nIf you want to process the results\n")
results = []
with contextlib.closing(mp.Pool(8)) as pool:
for i in range(5):
for j in range(20):
results.append(pool.apply_async(worker, args=(i,j)))
for result in results:
result.get()
pool.join()
答案 1 :(得分:0)
来自Pool.map的文件(强调我的):
map()内置函数的并行等价物(它只支持一个可迭代的参数)。 阻止,直到结果准备好。
在每个元素准备好之前,结果都无法准备好。只有在流程池中的工作完成后,每个元素才会准备就绪。因此,循环的最后一行:
pool_processes.map(filter_allft, chuncks)
在将filter_allft
应用于chuncks
的每个元素之前,才会完成。只有在发生这种情况后才会执行循环的下一次迭代。
然而,您的示例中没有代码显式清理进程池(终止其进程或加入它们)。因此,它们只会在垃圾收集器收集池时终止。当新池替换pool_processes
变量中的旧池时,很可能会在循环的 next 迭代中发生这种情况。
因此,虽然在下一次迭代开始之前所有工作都已完成,但在下一次迭代开始之前,这些过程将不会被清除。如果引用计数系统清理了池,则在下一次迭代创建任何 more 进程之前,至少会终止其进程。如果你必须依赖循环检测器,你可能会同时拥有多个活动池。
为避免这种情况,您可以添加一个明确的:
pool_processes.terminate()
pool_processes.join()
到循环结束。