CPU 使用 Python 多处理并行化时空闲
CPU idle when parallelising using Python multiprocessing
我已经使用 Python 的 multiprocessing
将一个函数并行化到一个包含各种参数的列表上,并且每个进程都会在中途冻结。发生这种情况时,我在 Ubuntu 机器上检查 top
,然后检查 1
,发现核心现在大部分都处于空闲状态 (https://man7.org/linux/man-pages/man1/top.1.html)。
这是我的代码:
from multiprocessing import Pool, Queue
class Parallelisable:
# Adapted from:
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 个子进程 运行。我猜这可以通过强制子进程 call execve
using the multiprocessing
spawn
method 来解决
function
in parallelise()
and _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])
好像是因为子进程占用内存大,Python默默杀掉了。父进程只是等待子进程return。我使用 dmesg -T| grep -E -i -m10 -B20 'killed process'
检查了终止进程的原因,其中 -m
指定了与 return 的最大匹配数,而 -B
指定了匹配“终止进程”之前的行数。
有关更多可能的原因和故障排除提示,请查看问题描述和问题中的评论。其中包括一些需要注意的事项以及 viztracer
追踪所发生事件的建议。引用 @minker:
viztracer
will output the file if the script is stuck. Just Ctrl-C out of it. Just remember you need --log_multiprocess
for multiprocessing
library when you use viztracer
.
我已经使用 Python 的 multiprocessing
将一个函数并行化到一个包含各种参数的列表上,并且每个进程都会在中途冻结。发生这种情况时,我在 Ubuntu 机器上检查 top
,然后检查 1
,发现核心现在大部分都处于空闲状态 (https://man7.org/linux/man-pages/man1/top.1.html)。
这是我的代码:
from multiprocessing import Pool, Queue
class Parallelisable:
# Adapted from:
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 个子进程 运行。我猜这可以通过强制子进程 callexecve
using themultiprocessing
spawn
method 来解决
function
inparallelise()
and_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])
好像是因为子进程占用内存大,Python默默杀掉了。父进程只是等待子进程return。我使用 dmesg -T| grep -E -i -m10 -B20 'killed process'
检查了终止进程的原因,其中 -m
指定了与 return 的最大匹配数,而 -B
指定了匹配“终止进程”之前的行数。
有关更多可能的原因和故障排除提示,请查看问题描述和问题中的评论。其中包括一些需要注意的事项以及 viztracer
追踪所发生事件的建议。引用 @minker:
viztracer
will output the file if the script is stuck. Just Ctrl-C out of it. Just remember you need--log_multiprocess
formultiprocessing
library when you useviztracer
.