【发布时间】:2020-12-16 20:44:16
【问题描述】:
我已经使用 Python 的 multiprocessing 将一个函数并行化到一个包含各种参数的列表上,并且每个进程都会在中途冻结。发生这种情况时,我在 Ubuntu 机器上检查top,然后是1,发现内核现在大部分都处于空闲状态(https://man7.org/linux/man-pages/man1/top.1.html)。
这是我的代码:
from multiprocessing import Pool, Queue
class Parallelisable:
# Adapted from: https://stackoverflow.com/questions/41992810/python-multiprocessing-across-different-files
def _apply_function(self, function, args_queue):
while not args_queue.empty():
args = args_queue.get()
# Apply function to arguments
function(*args)
def parallelise(self, function, args_list):
queue = Queue()
for args in args_list:
queue.put(args)
pool = Pool(None, self._apply_function, (function, queue,))
pool.close() # signal that we won't submit any more tasks to pool
pool.join() # wait until all processes are done
if __name__ == '__main__':
# Define data_dir, output_dir, filenames and some_frozenset here
# data_dir and output_dir are strings
# filenames is a list of strings
# some_frozenset is a frozenset of strings
Parallelisable().parallelise(some_function, [(filename, data_dir, output_dir, some_frozenset) for filename in filenames])
我怀疑这是由于死锁造成的。
我想出了这些可能的解释,但它们对我来说没有多大意义:
-
Parallelisable对象是共享资源,其中一个子进程在任何一个时间点获取锁,并防止在多个子进程中调用self._apply_function()。我认为情况并非如此,因为我有 2 个子进程同时运行。我猜这可以通过强制子进程到callexecveusing themultiprocessingspawnmethod来解决 -
functioninparallelise()和_apply_function()是共享资源,类似于上面的第 1 点 - 我的一些代码不在
__main__中,但我不认为这是一个问题,因为我在 Ubuntu 而不是 Windows 上运行 - 其中一个参数
(filename, data_dir, output_dir, some_frozenset)不是线程安全的,因为前 3 个是不可变字符串,最后一个是一组不可变的不可变字符串,所以不应该是这种情况
我有什么遗漏的吗?
顺便说一句,我认为我可以像这样重写上面的代码:
from multiprocessing import Pool
def parallelise_v2(function, args_list):
with Pool(None) as pool: # Use the "spawn" method if I want to call execve
pool.starmap_async(function, args_list)
if __name__ == '__main__':
# Define data_dir, output_dir, filenames and some_frozenset here
parallelise_v2(some_function, [(filename, data_dir, output_dir, some_frozenset) for filename in filenames])
【问题讨论】:
-
在stackoverflow中获得更多编码问题答案的一个技巧是制作一个比运行更小的程序。然后,人们可以运行您的代码,而不是查看源代码并试图弄清楚发生了什么。使用 viztracer 检查这里发生的事情将是一个非常有趣的案例,但不是没有一些可执行代码。
-
您的任务是否有可能在“大小”上不相等,所以您只有一个进程在完成其余的工作?或者您的任务是绑定在磁盘上还是等待网络资源或其他什么?您的所有进程都可以在不使用所有 CPU 的情况下运行。与上述评论相呼应,如果您提供了一个重现问题的可运行示例,我会进一步研究它。
-
谢谢@minker,这看起来真的很有用,我会研究一下。如果脚本中途卡住,
viztracer还会输出 json/html 文件吗?我没有提供实际代码,因为它对特定于任务的文件执行某些操作,我将尝试获取一些复制情况的最小代码。 -
@Macattack 任务不受 IO 限制,否则它会显示来自
top命令的高“wa, IO-wait”值。相反,CPU 内核都接近 100% “id, idle”。我正在使用服务器,据我所知代码/CPU/文件应该在同一台机器上,所以它不应该是网络问题。 -
viztracer会在脚本卡住时输出文件。只需 Ctrl-C 即可。请记住,当您使用 viztracer 时,您需要--log_multiprocess用于多处理库。
标签: python multiprocessing fork deadlock