Python在大文件写入时无声地挂起

时间:2019-01-02 13:36:38

标签: python file serialization yaml pickle

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

列表的长度约为500000个元素

每个元素都是一个int_size(〜2048,2)的nd_array。阵列具有不同的形状。

我(当前)使用的方法是

@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)

我也尝试了泡菜,它也给出了相同的问题

在较小的列表(约3400长)上,这可以很好地完成,并且速度足够快(<30秒)。

在约6000个长列表中,此过程在约2分钟后结束。

列表变大时,该过程似乎什么也没做。 RAM或磁盘活动没有变化。

30分钟后,我不再等待。

在强制停止该过程后,文件突然变得很大(〜600MB)。 我不知道它是否写完了。

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

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

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

2 个答案:

答案 0 :(得分:1)

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

当我在需要快速循环的应用程序上工作时,我发现代码中的某些内容非常慢。它正在打开/关闭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不能真正处理大型数组。此外,如果您已在列表中加载了其中的几个。从速度和内存的角度出发,始终一次处理一个,两个阵列。其余的必须在磁盘上等待。因此,将对象作为路径而不是对象引用,并在需要时从磁盘加载它。

您还说过,您不想手动组装列表。

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

>>> 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数组。

答案 1 :(得分:1)

对于代码

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)
在使用Python 3.7和PyYAML 3.13的系统(MacOSX,i7、16 GiB RAM,SSD)上,

完成时间为61分钟。在保存过程中,python进程占用了大约5 GB的内存,最终文件大小为2 GB。这也显示了文件格式的开销:由于数据大小为50k * 2048 * 2 * 8(在python中,float的大小通常为64位)= 1562 MB,意味着yaml差了1.3倍(并且序列化/反序列化也需要时间。

要回答您的问题:

  1. 没有正确或不正确的方法。进行进度更新并 估算完成时间并不容易(例如:其他任务可能 干扰估计,可以使用内存等资源 等等)。您可以依靠支持该库的库或实施该库 自己一些(如其他答案所建议)
  2. 不确定“调试”是正确的术语,因为在实践中可能只是过程缓慢而已。进行性能分析并不容易,尤其是在以下情况下 使用多个/不同的库。我一开始会很清楚 要求:您要从文件中保存什么?他们需要吗 是yaml吗?将50k数组另存为yaml似乎不是最佳解决方案 如果您关心性能。您是否应该首先问自己“哪种格式最适合我想要的?” (但您没有提供详细信息,所以不能说...)

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

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的文件(无开销)。当然,在与yaml不同的情况下应该使用pickle格式...