用Python锁定免费只读列表?

Pha*_*aun 9 python performance numpy

我已经做了一些基本的性能和内存消耗基准测试,我想知道是否有任何方法可以让事情变得更快......

  1. 我有一个巨大的70,000元素列表,其中包含numpy ndarray,以及所述列表中元组中的文件路径.

  2. 我的第一个版本将列表的切片副本传递给python多进程模块中的每个进程,但是它会将ram使用率扩展到20多GB以上

  3. 第二个版本我将它移动到全局空间并通过索引(例如foo [i])在我的每个进程的循环中访问它,这似乎将它放入共享内存区域/ CoW语义中,因此它不会爆炸内存使用率(停留在~3 GB)

  4. 然而,根据性能基准测试/追踪,似乎大部分应用时间现在花在"获取"模式上......

所以我想知道是否有任何方式我可以以某种方式将此列表转换为某种无锁/只读,以便我可以取消部分获取步骤,以帮助加快访问速度.

编辑1:这是应用程序概要分析的前几行输出

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
   65 2450.903   37.706 2450.903   37.706 {built-in method acquire}
39320    0.481    0.000    0.481    0.000 {method 'read' of 'file' objects}
  600    0.298    0.000    0.298    0.000 {posix.waitpid}
   48    0.271    0.006    0.271    0.006 {posix.fork}
Run Code Online (Sandbox Code Playgroud)

编辑2:这是列表结构的一个例子:

# Sample code for a rough idea of how the list is constructed
sim = []
for root, dirs, files in os.walk(rootdir):
    path = os.path.join(root, filename)
    image= Image.open(path)
    np_array = np.asarray(image)
    sim.append( (np_array, path) )

# Roughly it would look something like say this below
sim = List( (np.array([[1, 2, 3], [4, 5, 6]], np.int32), "/foobar/com/what.something") )
Run Code Online (Sandbox Code Playgroud)

此后,SIM列表将是只读的.

Sve*_*ach 11

multiprocessing模块提供了您所需要的:带有可选锁定的共享数组,即multiprocessing.Array类.传递lock=False给构造函数以禁用锁定.

编辑(考虑到您的更新):事情实际上比我最初预期的要多得多.列表中所有元素的数据需要在共享内存中创建.无论是将列表本身(即指向实际数据的指针)放在共享内存中,都无关紧要,因为与所有文件的数据相比,这应该是一个小的.要将文件数据存储在共享内存中,请使用

shared_data = multiprocessing.sharedctypes.RawArray("c", data)
Run Code Online (Sandbox Code Playgroud)

data您从文件中读取的数据在哪里.要在其中一个进程中将其用作NumPy数组,请使用

numpy.frombuffer(shared_data, dtype="c")
Run Code Online (Sandbox Code Playgroud)

这将为共享数据创建NumPy数组视图.同样,要将路径名放入共享内存,请使用

shared_path = multiprocessing.sharedctypes.RawArray("c", path)
Run Code Online (Sandbox Code Playgroud)

其中path是普通的Python字符串.在您的进程中,您可以使用它作为Python字符串访问它shared_path.raw.现在附加(shared_data, shared_path)到您的列表中.该列表将被复制到其他进程,但实际数据不会.

我最初打算用一个multiprocessing.Array实际的列表.这将是完全可能的并且将确保列表本身(即指向数据的指针)也在共享存储器中.现在我觉得这根本不重要,只要实际数据是共享的.