我有一些大的(甚至是大约10GB的压缩文件)文件,其中包含一个ASCII标头,然后原则上每个大约3MB的numpy.recarrays,我们称之为“事件”。我的第一种方法看起来像这样:
f = gzip.GzipFile(filename)
f.read(10000) # fixed length ascii header
event_dtype = np.dtype([
('Id', '>u4'), # simplified
('UnixTimeUTC', '>u4', 2),
('Data', '>i2', (1600,1024) )
])
event = np.fromfile( f, dtype = event_dtype, count=1 )
然而,这是不可能的,因为np.fromfile需要一个真正的FILE对象,因为它确实进行了低级别的调用(找到一个非常旧的票证https://github.com/numpy/numpy/issues/1103)。
据我了解,我必须这样做:
s = f.read( event_dtype.itemsize )
event = np.fromstring(s, dtype=event_dtype, count=1)
是的,它有效!但这不是非常低效吗?是不是分配了内存,为每个事件收集垃圾? 在我的笔记本电脑上,我达到了16个事件/秒,即~50MB / s
我想知道是否有人知道一个聪明的方法,分配一次mem然后让numpy直接读到那个mem。
顺便说一下。我是一名物理学家,所以......还是这个行业的新手。
答案 0 :(得分:5)
@Bakuriu可能是正确的,这可能是微观优化。你的瓶颈几乎肯定是IO,之后就是减压。将记忆分配两次可能并不重要。
但是,如果您想避免额外的内存分配,可以使用numpy.frombuffer
将字符串视为numpy数组。
这可以避免重复内存(字符串和数组使用相同的内存缓冲区),但默认情况下该数组将是只读的。如果需要,您可以将其更改为允许写入。
在您的情况下,只需将fromstring
替换为frombuffer
即可:
f = gzip.GzipFile(filename)
f.read(10000) # fixed length ascii header
event_dtype = np.dtype([
('Id', '>u4'), # simplified
('UnixTimeUTC', '>u4', 2),
('Data', '>i2', (1600,1024) )
])
s = f.read( event_dtype.itemsize )
event = np.frombuffer(s, dtype=event_dtype, count=1)
只是为了证明使用这种方法不会重复内存:
import numpy as np
x = "hello"
y = np.frombuffer(x, dtype=np.uint8)
# Make "y" writeable...
y.flags.writeable = True
# Prove that we're using the same memory
y[0] = 121
print x # <-- Notice that we're outputting changing y and printing x...
这会产生:yello
而不是hello
。
无论在这种特殊情况下它是否是一个重要的优化,它都是一个有用的方法需要注意。