gpt4 book ai didi

python - 在不复制的情况下在多个进程之间共享非常大的字典的最快方法

转载 作者:行者123 更新时间:2023-12-03 20:57:36 30 4
gpt4 key购买 nike

TL;DR:如何以一种高性能的方式在多个进程之间共享一个大 (200MB) 只读 dict,在没有每个进程在内存中拥有完整副本的情况下,它会被大量访问。

编辑:看起来如果我只是将字典作为 multiprocessing.Pool/Process 的参数传递,除非工作人员修改字典,否则它实际上不会创建副本。我只是假设它会复制。这种行为似乎只是在 fork 可用的 Unix 上,即使这样也并非总是如此。但如果是这样,它应该可以解决我的问题,直到将其转换为 ETL 作业。

我正在尝试做的事情:

我有一项任务来改进将数据从一个商店复制到另一个商店的脚本。对数据进行标准化和转换。此任务适用于来自源文档存储的大约 1 亿个文档,这些文档被汇总并推送到另一个目标文档存储。

每个文档都有一个 ID,还有另一个文档存储,本质上是这些 ID 的键值存储映射到此任务所需的一些附加信息。这个存储要小得多,并且在来自主存储的文档通过时对其进行查询,这不是没有大量缓存的真正选择,并且大量缓存最终会很快成为整个事物的副本。我只是在开始任何事情之前从整个商​​店创建整个字典字典并使用它。该词典大小约为 200MB。请注意,这本词典只能被读取。

为此,我设置了多处理并有大约 30 个并发进程。我已经为每个流程划分了工作,这样每个流程都达到了不同的指标,并且可以在大约 4 小时内完成整个过程。

我注意到在做以下两件事时我对 CPU 非常敏感:

  • 使用线程池/线程(我目前正在做的事情),因此每个线程都可以毫无问题地访问 dict。 GIL 正在杀死我,我有一个进程一直以 100% 的速度最大化,而其他 CPU 处于空闲状态。切换到 PyPy 有很大帮助,但我仍然对这种方法不满意。
  • 为大字典创建一个 Multiprocessing.Manager().dict() 并让子进程通过它访问。此方法创建的服务器进程始终处于 100% cpu。我不知道为什么,因为我只看过这本字典,所以我怀疑这是一个锁定的东西。我不知道 Manager 在内部是如何工作的,但我猜测子进程正在通过管道/套接字连接每次获取,并且开销很大。它还表明,如果为真,使用 Reddis/Memcache 也会有同样的问题。也许它可以配置得更好?

  • 做这些事情时,我是内存受限的:
  • 使用 SharedMemory View 。您似乎无法像我需要的那样对 dicts 执行此操作。我可以将 dict 序列化以进入共享 View ,但要使其在 Child 进程上可用,您需要将数据序列化为实际可用的 dict,从而在进程中创建副本。

  • 我强烈怀疑,除非我错过了一些东西,否则我将不得不“下载更多内存”或从 Python 重写为没有 GIL 的东西(或使用 ETL 就像它应该在......中那样做)。

    在 ram 的情况下,存储这样的 dict 以减少刺痛的最有效方法是什么?它目前是一个标准字典,映射到由 3 个长/浮点组成的额外信息的元组。

    doc_to_docinfo = {
    "ID1": (5.2, 3.0, 455),
    }

    对于这个用例,是否有比我正在做的更有效的哈希图实现?

    最佳答案

    你似乎和我有类似的问题。可以使用我的源here为每个线程创建这些字典键的分区。我的建议:将文档 ID 拆分为长度为 3 或 4 的分区,使所有进程/线程的分区表保持同步,然后将文档的各个部分移动到每个进程/线程,并将该进程作为入口点进行字典查找并找出哪个进程可以处理该字典的部分。如果您很聪明地平衡了分区,您还可以管理每个线程的等量文档。

    关于python - 在不复制的情况下在多个进程之间共享非常大的字典的最快方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60139306/

    30 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com