Python 在写入大文件时静默挂起

Python hangs silently on large file write

我正在尝试将一大堆 numpy nd_arrays 写入磁盘。

列表长约 50000 个元素

每个元素都是 nd_array 大小 (~2048,2) 的整数。数组有不同的形状。

我(目前)使用的方法是

@staticmethod
def _write_with_yaml(path, obj):
    with io.open(path, 'w+', encoding='utf8') as outfile:
        yaml.dump(obj, outfile, default_flow_style=False, allow_unicode=True)

我也试过 pickle 也有同样的问题 :

在小列表(~3400 长)上,这工作正常,完成速度足够快(<30 秒)。

在约 6000 个长列表中,这将在约 2 分钟后完成。

当列表变大时,进程似乎什么都不做。 RAM 或磁盘没有变化 activity。

我等了 30 分钟后就不再等了。

强制停止进程后,文件突然变得很大(~600MB)。 不知道写完没有。

写这么大的列表的正确方法是什么,知道他写是否成功,如果可能的话,知道write/read什么时候完成?

当进程似乎挂起时,我如何调试正在发生的事情?

我不想在我的代码中手动中断和 assemble 列表,我希望序列化库能够为我做到这一点。

我不能说这就是答案,但可能就是答案。

当我在开发需要快速循环的应用程序时,我发现代码中的某些部分非常慢。它正在打开/关闭 yaml 文件。

使用JSON解决了。

除了作为您不经常打开的某种配置之外,不要将 YAML 用于任何其他用途。

你的阵列保存解决方案:

np.save(path,array) # path = path+name+'.npy'

如果您确实需要保存数组列表,我建议您使用数组路径保存列表(数组本身将使用 np.save 保存在磁盘上)。在磁盘上保存 python 个对象并不是您真正想要的。你想要的是用 np.save

保存 numpy 数组

完整解决方案(保存示例):

for array_index in range(len(list_of_arrays)):
    np.save(array_index+'.npy',list_of_arrays[array_index])
    # path = array_index+'.npy'

完整解决方案(加载示例):

list_of_array_paths = ['1.npy','2.npy']
list_of_arrays = []
for array_path in list_of_array_paths:
    list_of_arrays.append(np.load(array_path))

进一步的建议:

Python 无法真正处理大数组。此外,如果您已经在列表中加载了其中的几个。从速度和内存的角度来看,总是一次处理一个、两个数组。其余的必须在磁盘上等待。因此,不是对象引用,而是将引用作为路径,并在需要时从磁盘加载它。

另外,您说过您不想 assemble 手动添加列表。

可能的解决方案,我不建议,但可能正是您正在寻找的解决方案

>>> a = np.zeros(shape = [10,5,3])
>>> b = np.zeros(shape = [7,7,9])
>>> c = [a,b]
>>> np.save('data.npy',c)
>>> d = np.load('data.npy')
>>> d.shape
(2,)
>>> type(d)
<type 'numpy.ndarray'>
>>> d.shape
(2,)
>>> d[0].shape
(10, 5, 3)
>>> 

我相信我不需要评论上面提到的代码。但是,加载回来后,您将丢失列表,因为列表将被转换为 numpy 数组。

求代码

import numpy as np
import yaml

x = []
for i in range(0,50000):
    x.append(np.random.rand(2048,2))
print("Arrays generated")
with open("t.yaml", 'w+', encoding='utf8') as outfile:
    yaml.dump(x, outfile, default_flow_style=False, allow_unicode=True)

在我的系统(MacOSX、i7、16 GiB RAM、SSD)上,Python 3.7 和 PyYAML 3.13 完成时间为 61 分钟。在保存过程中,python 进程占用了大约 5 GB 的内存,最终文件大小为 2 GB。这也显示了文件格式的开销:因为数据的大小是 50k * 2048 * 2 * 8(float 的大小在 python 中一般是 64 位)= 1562 MBytes,意味着 yaml 在 1.3 左右更糟(serialisation/deserialisation 也需要时间)。

回答您的问题:

  1. 没有正确或不正确的方法。有进展更新和 估计完成时间并不容易(例如:其他任务可能 干扰估计,可以使用内存等资源 向上等)。您可以依赖支持或实现的库 你自己的东西(正如其他答案所建议的那样)
  2. 不确定 "debug" 是不是正确的术语,因为在实践中,这个过程可能很慢。进行性能分析并不容易,尤其是如果 使用 multiple/different 个库。我要开始的很清楚 要求:你想从保存的文件中得到什么?他们需要 是 yaml?将 50k 数组保存为 yaml 似乎不是最佳解决方案 如果你关心性能。你应该先问问自己"which is the best format for what I want?"(但你没有说详细所以不能说...)

编辑:如果您想要快速的东西,请使用 pickle。代码:

import numpy as np
import yaml
import pickle

x = []
for i in range(0,50000):
    x.append(np.random.rand(2048,2))
print("Arrays generated")
pickle.dump( x, open( "t.yaml", "wb" ) )

在 9 秒内完成,并生成一个 1.5GBytes 的文件(无开销)。当然 pickle 格式应该在与 yaml 非常不同的情况下使用...