"worker" 和 "task" for concurrent.futures.ProcessPoolExecutor 之间的区别



我有一个"令人尴尬的平行";在python上运行的问题,我想我可以使用concurrent.futures模块来并行化这个计算。我以前已经成功地做到了这一点,这是我第一次尝试在比我的笔记本电脑更强大的电脑上做到这一点。这台新机器有32个内核/64个线程,而我的笔记本电脑只有2/4个。

我正在使用concurrent.futures库中的ProcessPoolExecutor对象。我将max_workers参数设置为10,然后在循环中一个接一个地提交我的所有作业(其中可能有100个(。模拟似乎有效,但有些行为我不理解,即使在激烈的谷歌搜索之后也是如此。我在Ubuntu上运行这个,所以我使用htop命令来监视我的处理器。我看到的是:

  1. 创建了10个进程
  2. 每个进程请求>100%的CPU功率(例如,高达600%(
  3. 还创建了一大堆流程。(我认为这些是"任务",而不是进程。当我键入SHIFT+H时,它们就会消失。(
  4. 最令人担忧的是,看起来所有处理器的假脱机率都高达100%。(我说的是终端顶部的"均衡器条":

htop 屏幕截图

我的问题是——如果我只解雇了10名员工,为什么我的所有处理器似乎都在以最大容量使用?我的工作理论是,我称之为";保留,";而其他处理器只是跳进来帮忙。。。如果其他人运行其他任务并要求一些处理能力(但不包括我要求的10名员工(,我的其他任务会放弃并归还。但是这不是什么";创建10个进程";我直觉上感觉像。

如果你想要一个MWE,这大致就是我的代码:

def expensive_function(arg):
a = sum(list(range(10 ** arg)))
print(a)
return a

def main():
import concurrent.futures
from random import randrange
with concurrent.futures.ProcessPoolExecutor(max_workers=4) as executor:
# Submit the tasks
futures = []
for i in range(100):
random_argument = randrange(5, 7)
futures.append(executor.submit(expensive_function, random_argument))
# Monitor your progress:
num_results = len(futures)
for k, _ in enumerate(concurrent.futures.as_completed(futures)):
print(f'********** Completed {k + 1} of {num_results} simulations **********')

if __name__ == '__main__':
main()

由于GIL的原因,一个进程在给定时间只能有1个线程执行python字节码,所以如果你有10个进程,那么在给定时间应该有10个线程(因此是核心(执行python字节代码,但这并不是全部。

expensive_function是不明确的,python可以创建10个工作进程,因此在给定的时间(+主进程(只能有10个内核执行python代码(由于GIL(,但是,如果expensive_function使用外部C模块(不必遵守GIL(进行某种多线程处理,那么10个进程中的每一个进程都可以有Y个线程并行工作,因此在给定的时间内总共有10*Y个内核被使用,例如,您的代码可能在10个进程的每个进程上外部运行6个线程,总共有60个线程在60个内核上同时运行。

然而,这并不能真正回答你的问题,所以主要的答案是,workers是在给定时间可以执行python字节码的进程(核心(的数量(特别强调"python字节码"(,其中tasks是你的workers将执行的任务总数,当任何worker完成手头的任务时,它将启动另一个任务。

相关内容

  • 没有找到相关文章

最新更新