我有两个程序,一个用C编写,一个用Python编写。我想从 Python 向 C 程序传递一些参数并并行执行多次,因为我有大约 100 万个这样的 C 调用。
本质上我是这样做的:
from subprocess import check_call
import multiprocessing as mp
from itertools import combinations
def run_parallel(f1, f2):
check_call(f"./c_compiled {f1} {f2} &", cwd='.', shell=True)
if __name__ == '__main__':
pairs = combinations(fns, 2)
pool = mp.Pool(processes=32)
pool.starmap(run_parallel, pairs)
pool.close()
但是,有时我会收到以下错误(尽管主进程仍在运行(
/bin/sh: fork: 重试: 没有子进程
此外,有时Python中的整个程序会失败
正在阻止IOError: [错误 11] 资源暂时不可用
我发现当它仍在运行时,我可以看到为我的用户生成了很多进程(大约 500 个(,而我最多有 512 个可用进程。
这不会一直发生(取决于参数(,但经常发生。如何避免这些问题?
我敢打赌你遇到了进程/文件描述符/...限制在那里。
您可以通过不使用shell=True
来"保存"每个调用的一个进程:
check_call(["./c_compiled", f1, f2], cwd='.')
但是,最好还是使C代码可以从Python调用,而不是创建进程来执行此操作。 到目前为止,将"随机"C代码与Python接口的最简单方法是Cython。
多次并行"你当然可以做到,对于"许多"的合理值,但是"大约100万个这样的C调用"在同一台机器上同时运行几乎肯定是不可能的。
正如@AKX的回答中所讨论的那样,您可以通过在不插入 shell 的情况下运行作业来减轻负载,但这还不足以将您的目标纳入范围。更好的方法是将作业排队,以便一次只运行几个作业- 一旦达到该数量的作业,请仅在前一个作业完成时才开始一个新作业。您应该尝试保持并发运行的确切数字取决于您的计算机和计算的细节,但围绕 CPU 内核数量可能是一个很好的初步猜测。
特别要注意的是,在任何时候拥有的作业多于计算机同时运行的资源,都会适得其反。 如果进程执行很少或没有 I/O,则计算机中的内核数量会限制这一点,因为只有在任何给定时间(每个内核最多一个(在内核上调度的进程才会取得进展,而其他进程则等待。 在许多进程之间切换以避免使任何一个进程匮乏会增加开销。 如果你的进程执行大量的 I/O,那么它们可能会花费相当一部分时间在 I/O 上阻塞,因此不需要(直接(一个内核,但在这种情况下,你的 I/O 设备很可能会造成瓶颈,这可能比内核数量的限制更糟糕。