在 Python 3 中确定 max_workers 用于多处理的最佳值的好方法是啥?

Posted

技术标签:

【中文标题】在 Python 3 中确定 max_workers 用于多处理的最佳值的好方法是啥?【英文标题】:What is a good way to determine the optimal value of max_workers for multi-processing in Python 3?在 Python 3 中确定 max_workers 用于多处理的最佳值的好方法是什么? 【发布时间】:2020-10-22 15:38:23 【问题描述】:

我有一个用于自动化的 Python 脚本。它运行系统命令并将结果存储在数据库中。它包含以下行:

ThreadPoolExecutor(max_workers = 3)

我不知道将 max_workers 设置为什么值。我见过有人说max_workers的最优值?我听说人们说这取决于机器,但没有进一步详细说明。我还读到 Python 3 中的默认值是处理器数量 * 5。如果没有普遍最优的解决方案,那么有什么好方法可以接近这个问题的局部最优解决方案?

【问题讨论】:

【参考方案1】:

Brian Goetz 在他的名著《Java Concurrency in Practice》中推荐了以下公式:

线程数 = 可用内核数 * (1 + 等待时间 / 服务时间)

等待时间 - 等待 IO 绑定任务完成所花费的时间,例如等待来自远程服务的 HTTP 响应。

(不仅是IO绑定的任务,可能是等待获得监视器锁的时间或线程处于WAITING/TIMED_WAITING状态的时间)

服务时间 - 是忙于处理 HTTP 响应、编组/解组、任何其他转换等的时间。

等待时间/服务时间 - 这个比率通常称为阻塞系数。

计算密集型任务的阻塞系数接近 0,在这种情况下,线程数等于可用内核数。如果所有任务都是计算密集型的,那么这就是我们所需要的。拥有更多线程无济于事。

例如:

工作线程调用微服务,将响应序列化为 JSON 并执行一些规则。微服务响应时间为50ms,处理时间为5ms。我们将应用部署到具有双核 CPU 的服务器上:

2 * (1 + 50 / 5) = 22 // 最佳线程池大小

但是这个例子过于简单了。除了 HTTP 连接池之外,您的应用程序可能还有来自 JMS 的请求,并且可能还有 JDBC 连接池。

如果您有不同类别的任务,最好使用多个线程池,这样每个线程池都可以根据其工作负载进行调整。

全文你可以找到here

【讨论】:

【参考方案2】:

试试

import os
max_workers = os.cpu_count()

【讨论】:

这只是告诉我计算机的逻辑处理器数量,即 8。将其设置为该值似乎不是最佳值,因为 max_workers 的默认值为 8 * 5,这是一个不仅仅是 8 个。 我建议的是当前实践中的locally optimal 解决方案。实际数字取决于您要执行的任务,当然,您可以对其进行调整。

以上是关于在 Python 3 中确定 max_workers 用于多处理的最佳值的好方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

在 Python 中使用 ProcessPoolExecutor 的运行调用数不正确

进程池,线程池,协程

python_并发编程——线程池

python多线程并行计算通过向线程池ThreadPoolExecutor提交任务的实现方法

从 CSV 确定数据类型 - Python

使用 ProcessPoolExecutor 时更新变量