为什么 python 的 ThreadPoolExecutor 工作队列接受的项目数似乎超过其最大工作数?

Why does python's ThreadPoolExecutor work queue appear to accept more items than its maximum workers?

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。我预计我向执行程序发出的请求数等于放入线程执行程序队列的作业数。

为什么会这样?我怎样才能将这个数字限制为最大工人数?

self.executor._work_queue.qsize() returns 中等待线程执行的请求数似乎 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 之后才开始变大,因此额外的请求会进入队列。