python 中的 ThreadPoolExecutor 是否真的有效

Does ThreadPoolExecutor in python really work

我正在尝试使用多线程编写更快的 python 代码。我不想使用 ProcessPoolExecutor 来保存内存消耗。

所以,当我使用 ThreadPoolExecutor.map 将迭代器映射到函数时。它真的不起作用代码所花费的时间并没有真正得到增强。然后我在 python 中阅读了有关 GIL 的内容,我的问题是:如果 GIL 应用于所有人,为什么他们创建 ThreadPoolExecutor.map,或者有没有更好的想法使用 ThreadPoolExecutor.map.

请找一个我用来理解这个过程的例子。我很高兴听到关于如何为迭代器使用多线程而不是多进程的建议,因为我的内存卡和 cpus 不是那么高。

import concurrent.futures
import math

PRIMES = [
    112272535095293,
    112582705942171,
    112272535095293,
    115280095190773,
    115797848077099,
    1099726899285419]

def is_prime(n):
    if n < 2:
        return False
    if n == 2:
        return True
    if n % 2 == 0:
        return False

    sqrt_n = int(math.floor(math.sqrt(n)))
    for i in range(3, sqrt_n + 1, 2):
        if n % i == 0:
            return False
    return True

def main():
    with concurrent.futures.ThreadPoolExecutor(max_workers = 4) as executor:
        future= executor.map(is_prime, PRIMES)

    print(future.result())

if __name__ == '__main__':
    main()

如您所述,GIL 意味着一次只能使用 1 个 CPU,并且只有 1 个 "real" 线程。所以使用线程池不会加速 CPU-bound 代码。但是,标准库和其他 3rd 方库中的许多函数如果在 I/O.

上被阻止,将自动释放 GIL

例如,如果您有代码试图从互联网上下载很多东西,您可以使用 Python 线程池。当一个线程请求下载某些东西并等待响应时,它可以(取决于您使用什么库来发出 HTTP 请求)释放 GIL 并给另一个线程一个机会 运行。这意味着您可以在任何请求完成之前发出许多请求,然后每个 Python 线程将在响应可用时再次被唤醒。这种 Python 多线程可以带来巨大的性能提升。