首页 > 解决方案 > 为什么 python 的 ThreadPoolExecutor 工作队列似乎接受的项目超过了它的最大工作人员?

问题描述

import time
from concurrent.futures import ThreadPoolExecutor


class Sandbox:
    def __init__(self, n=5):
        self.n = n
        self.executor = ThreadPoolExecutor(n)

    def make_request(self):
        if self.executor._work_queue.qsize() < self.n:
            self.executor.submit(self.do_something_that_takes_long)
            print('HTTP_202')
        else:
            print('HTTP_429')

    def do_something_that_takes_long(self):
        time.sleep(10)


def do_ok_situation():
    s = Sandbox()
    for _ in range(5):
        s.make_request()


def do_bad_situation():
    s = Sandbox()
    for _ in range(100):
        s.make_request()


# do_ok_situation()
do_bad_situation()

这将输出

HTTP_202
HTTP_202
HTTP_202
HTTP_202
HTTP_202
HTTP_202
HTTP_202
HTTP_202
HTTP_202
HTTP_202
HTTP_429
HTTP_429
HTTP_429
HTTP_429
...

此代码将输出 10 个 HTTP_200(在我的机器上)而不是 5 个。我希望我向执行程序发出的请求数等于放入线程执行程序队列的作业数。

为什么会这样?如何将此数字限制为最大工作人员的数量?

标签: pythonmultithreadingexecutor

解决方案


似乎self.executor._work_queue.qsize()返回work_queue等待线程执行它们的请求数。但是,当您调用时submit(),线程池中通常有一个空闲线程可以立即处理请求,因此对于前五次调用make_request(),请求根本不会进入work_queue,而是直接交给线程执行。

您可以通过添加如下行来向自己展示这种行为

print("qSize=%i"%self.executor._work_queue.qsize())

make_request()在你的方法的前面;您会看到qSize前 5 次调用仍然为 0,并且只有在 ThreadPool 中的所有 5 个线程都已忙于执行something_that_takes_long并且因此其他请求进入队列后才开始变大。


推荐阅读