【问题标题】:Optimise network bound multiprocessing code优化网络绑定多处理代码
【发布时间】:2015-10-22 06:52:16
【问题描述】:

我有一个使用 multiprocessing.Pool 调用的函数

像这样:

from multiprocessing import Pool

def ingest_item(id):
    # goes and does alot of network calls
    # adds a bunch to a remote db
    return None

if __name__ == '__main__':
    p = Pool(12)
    thing_ids = range(1000000)
    p.map(ingest_item, thing_ids)

正在迭代的列表 pool.map 包含大约 100 万个项目, 对于每个ingest_item() 调用,它都会调用第 3 方服务并将数据添加到远程 Postgresql 数据库。

在 12 核机器上,它在 24 小时内处理约 1,000 个pool.map 项。 CPU 和 RAM 使用率低。

我怎样才能使这更快?

由于瓶颈似乎是网络调用,切换到线程是否有意义?

提前致谢!

【问题讨论】:

    标签: python


    【解决方案1】:

    首先:记住您正在执行网络任务。您应该期望您的 CPU 和 RAM 使用率较低,因为网络比您的 12 核机器慢几个数量级。

    也就是说,每个请求只有一个进程很浪费。如果您开始遇到启动过多进程的问题,您可以尝试 pycurl,如此处建议的 Library or tool to download multiple files in parallel

    这个 pycurl 示例看起来与您的任务 https://github.com/pycurl/pycurl/blob/master/examples/retriever-multi.py 非常相似

    【讨论】:

    • 我无法轻易更改函数中的代码。它执行很多任务和检查,网络调用也是通过 PyPi 上的包完成的,我不想只为这个任务花费数周的时间进行编辑。 (我宁愿租一台更高核心的机器也不要那样做)
    • 我还应该提到问题不在于进程的数量,我在机器上使用所有 12 个都很好。网络带宽也没有接近满。在理想情况下,我会神奇地为机器添加 100 个内核,但这很昂贵。
    • 一台 12 核机器上可以执行超过 12 个进程。试试 100 看看会发生什么。
    • 最终,您将不再看到增加进程数所带来的收益。这可能意味着您已经淹没了网络。此时,请考虑部署到连接速度更快的机器上。
    • 您有与此相关的链接吗?到目前为止,我一直在使用multiprocessing.cpu_count()。编辑:机器也有 1gb/s,目前只使用 1-2mb/s 左右
    【解决方案2】:

    使用线程不太可能显着提高性能。这是因为无论你如何分解任务,所有请求都必须通过网络。

    为了提高性能,您可能希望查看 3rd 方服务是否具有某种具有更好性能的批量请求 API。

    如果您的工作负载允许,您可以尝试使用某种缓存。但是,从您对任务的解释来看,这听起来影响不大,因为您主要是发送数据,而不是请求它。您还可以考虑缓存打开的连接(如果您还没有这样做),这有助于避免非常慢的 TCP 握手。这种类型的缓存通常用于网络浏览器(例如Chrome)。

    免责声明:我没有 Python 经验

    【讨论】:

    • 我已经实现了缓存,但这仅对重复请求有用(确实会发生,但不会加快我需要的数量)。要执行批量 api 请求选项,我必须在池中创建一个池,这不是一个好主意。
    • 也许瓶颈与网络延迟有关,可以通过保持连接打开来将其最小化,这样您就可以避免在每次调用 ingest_item 时重新打开连接而导致过多的 TCP 握手。我不确定 Python 是否默认执行此操作,但值得研究。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多