用Python锁定免费只读列表?

时间:2011-01-20 17:00:17

标签: python performance numpy

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

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

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

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

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

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

    编辑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}
    

    编辑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") )
    

    此后SIM卡列表将被读取。

1 个答案:

答案 0 :(得分:10)

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

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

shared_data = multiprocessing.sharedctypes.RawArray("c", data)

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

numpy.frombuffer(shared_data, dtype="c")

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

shared_path = multiprocessing.sharedctypes.RawArray("c", path)

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

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