【问题标题】:It takes longer to access shared memory then to load from file?访问共享内存然后从文件加载需要更长的时间?
【发布时间】:2018-10-02 13:44:38
【问题描述】:

我有一个非常大的文件加载到我的主进程中。我的目标是让多个进程同时从内存中读取,以避免内存限制并使其更快。

根据this的回答,我应该使用Shared ctypes Objects

管理器类型是为灵活性而非效率而构建的……这必然意味着复制任何有问题的对象。 .... 如果你想要共享物理内存,我建议使用Shared ctypes Objects。这些实际上确实指向内存中的一个公共位置,因此速度更快,资源也更少。

所以我这样做了:

import time
import pickle
import multiprocessing
from functools import partial

def foo(_, v):
    tp = time.time()
    v = v.value
    print(hex(id(v)))
    print(f'took me {time.time()-tp} in process')

if __name__ == '__main__':
    # creates a file which is about 800 MB
    with open('foo.pkl', 'wb') as file:
        pickle.dump('aaabbbaa'*int(1e8), file, protocol=pickle.HIGHEST_PROTOCOL)

    t1 = time.time()
    with open('foo.pkl', 'rb') as file:
        contract_conversion = pickle.load(file)
    print(f'load took {time.time()-t1}')

    m = multiprocessing.Manager()
    vm = m.Value(str, contract_conversion, lock=False)  # not locked because i only read from it so its safe
    foo_p = partial(foo, v=vm)

    tpo = time.time()
    with multiprocessing.Pool() as pool:
       pool.map(foo_p, range(4))
    print(f'took me {time.time()-tpo} for pool stuff')

但是我可以看到进程使用复制它(每个进程中的内存非常高)并且它比简单地从磁盘读取要慢得多。


印刷品:

load took 0.8662333488464355
0x1c736ca0040
took me 2.286606550216675 in process
0x15cc0404040
took me 3.178203582763672 in process
0x1f30f049040
took me 4.179721355438232 in process
0x21d2c8cc040
took me 4.913192510604858 in process
took me 5.251579999923706 for pool stuff

id 也不一样,虽然我不确定 id 是简单的 python 标识符还是内存位置。

【问题讨论】:

  • 不是将整个文件读取到共享内存中,您的每个子进程是否可以从磁盘仅读取它们的文件块?这取决于文件中的数据类型以及您是否知道要提前读取哪些段。
  • 并非如此,所有进程都使用相同的块,但方式不同。此处未显示,但我将其他参数传递给进程。
  • 如果您在内存中加载过多,您的 PC 可能会将部分内存保存在磁盘上(这称为“交换”),这会严重降低应用程序的性能。这里可能是这种情况吗?
  • 我的笔记本电脑上有大约 16 GB 的内存,即使我使用 'aaabbbaa' * int(1e7) 创建文件,从文件中检索共享数据所需的时间大约是其三倍。内存使用率不超过40%

标签: python multiprocessing shared-memory


【解决方案1】:

您没有使用共享内存。那将是multiprocessing.Value,而不是multiprocessing.Manager().Value。您将字符串存储在管理器的服务器进程中,并通过 TLS 连接发送泡菜以访问该值。此外,服务器进程在处理请求时受到其自身 GIL 的限制。

我不知道这些方面对开销的贡献有多大,但总体而言它比读取共享内存更昂贵。

【讨论】:

  • 我尝试使用ctypes.c_char_p 传递二进制对象,但我说的是c_char_p objects should only be shared between processes through inheritance
  • @moshevi:是的,我不确定是否有比通过全局更好的方式与子进程共享multiprocessing.Value。我看不出有什么办法让它通过args 工作。
  • “通过全球”是什么意思?除了 args,我不知道有任何其他方法可以将数据传递给子进程。
  • 显然可以通过为池提供initializerinitargs 来将值传递给工作人员。我现在没有时间测试它。
猜你喜欢
  • 2020-02-28
  • 2016-06-12
  • 1970-01-01
  • 2021-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-04
  • 2012-04-27
相关资源
最近更新 更多