Python 多线程/多处理并发并发速度非常慢

And*_*ris 6 python multithreading concurrent.futures

我正在尝试使用多线程和/或多处理来加速我的脚本。本质上,我有一个从 CSV 读取的 10,000 个子网列表,我想将其转换为 IPv4 对象,然后存储在数组中。

我的基本代码如下,执行时间大约为 300 毫秒:

aclsConverted = []
def convertToIP(ip):
    aclsConverted.append(ipaddress.ip_network(ip))

for y in acls:
    convertToIP(y['srcSubnet'])
Run Code Online (Sandbox Code Playgroud)

如果我尝试使用并发.futures 线程,它可以工作,但速度慢 3-4 倍,如下所示:

aclsConverted = []
def convertToIP(ip):
    aclsConverted.append(ipaddress.ip_network(ip))

with concurrent.futures.ThreadPoolExecutor(max_workers=20) as executor:
    for y in acls:
        executor.submit(convertToIP,y['srcSubnet'])
Run Code Online (Sandbox Code Playgroud)

然后,如果我尝试使用并发。futures 处理速度会慢 10-15 倍,并且数组为空。代码如下

aclsConverted = []
def convertToIP(ip):
    aclsConverted.append(ipaddress.ip_network(ip))

with concurrent.futures.ProcessPoolExecutor(max_workers=20) as executor:
    for y in acls:
        executor.submit(convertToIP,y['srcSubnet'])
Run Code Online (Sandbox Code Playgroud)

我运行它的服务器有 28 个物理核心。

任何关于我可能做错的事情的建议将不胜感激!

gel*_*ida 2

如果任务太小,那么管理多处理/多线程的开销通常比并行运行任务的好处更昂贵。

您可以尝试以下操作:

只是创建两个进程(不是线程!!!),一个处理前 5000 个子网,另一个处理其他 5000 个子网。

在那里您可能会看到一些性能改进。但您执行的任务不是 CPU 或 IO 密集型的,因此不确定它是否有效。

另一方面,Python 中的多线程对于没有 IO 并且是纯 Python 代码的任务来说根本没有任何性能改进。

原因就是臭名昭著的GIL(全局解释器锁)。在 python 中,你永远不能在同一进程中并行执行两个 python 字节代码。

python 中的多线程对于具有 IO(执行网络访问)、执行睡眠、调用模块、用 C 实现并释放 GIL 的任务仍然有意义。例如,numpy 释放了 GIL,因此是多线程的良好候选者

  • OP 两者都尝试过。但我最初的评论仍然有效。分派非常小的任务是不值得的。调度任务/收集结果的开销将是一个过高的惩罚。这就是为什么我建议一开始只尝试两个任务,每个任务在一个任务中处理 5000 行,但即使如此,如果工作实际上只是将子网转换为 IP 对象,我也不确定是否值得付出努力 (2认同)