如何在python中加快numpy数组填充?
|
我正在尝试使用以下代码填充预分配的字节数组:
# preallocate a block array
dt = numpy.dtype(\'u8\')
in_memory_blocks = numpy.zeros(_AVAIL_IN_MEMORY_BLOCKS, dt)
...
# write all the blocks out, flushing only as desired
blocks_per_flush_xrange = xrange(0, blocks_per_flush)
for _ in xrange(0, num_flushes):
for block_index in blocks_per_flush_xrange:
in_memory_blocks[block_index] = random.randint(0, _BLOCK_MAX)
print(\'flushing bytes stored in memory...\')
# commented out for SO; exists in actual code
# removing this doesn\'t make an order-of-magnitude difference in time
# m.update(in_memory_blocks[:blocks_per_flush])
in_memory_blocks[:blocks_per_flush].tofile(f)
一些要点:
num_flushes
低,在4-10附近
blocks_per_flush
是一个大数,数量级为数百万
in_memory_blocks
可以是一个相当大的缓冲区(我将其设置为低至1MB,高至100MB),但是时间安排非常合理...
_BLOCK_MAX
是8字节无符号整数的最大值
m
是a6ѭ
使用上面的代码生成1MB需要大约1s; 500MB需要376秒。相比之下,我使用rand()的简单C程序可以在8s内创建500MB文件。
如何在上述循环中提高性能?我敢肯定,我会忽略一些导致运行时如此巨大差异的明显原因。
没有找到相关结果
已邀请:
4 个回复
糖固傻染
这使用了“ 8”函数,该函数分配了整个内存块,并用随机整数填充它(请注意,塞巴斯蒂安·J.F。Sebastian在下面的评论中,分别是“ 8”和“ 10”)。 (据我所知)没有办法使用numpy随机例程填充预分配的数组。另一个问题是numpy \的randint返回int64数组。如果需要其他大小的整数,则可以使用numpy输入方法,例如numpy.uint8。如果要让randint覆盖类型的整个范围,请使用@J。 F. Sebastian的下面使用numpy.random.bytes的方法将是最好的(几乎在任何情况下都可以!)。 但是,简单的测试显示合理的时间(与C代码相同的数量级)。以下代码使用numpy方法测试分配20,000,000个随机整数的uint8数组的时间:
我在使用4年的Core2笔记本电脑上每次分配大约要花费0.7秒的时间(它运行50次,因此运行整个测试将花费更长的时间)。每个20,000,000个随机uint8整数的分配时间为0.7 s,因此我希望整个500MB的时间大约为20 s。 更多的内存意味着您可以一次分配更大的块,但是当您只需要8个块时,您仍然有效地浪费了时间为每个int分配和写入64位(我还没有量化这种效果)。如果仍然不够快,则可以使用numpy ctypes接口调用C实现。这真的很容易使用,并且与纯C语言相比,您几乎不会放慢速度。 一般的带回家的信息是,对于numpy,请始终尝试使用它们存在的numpy例程,并记住使用ctypes退回到C不会太痛苦。总的来说,这种方法可以非常有效地使用python,而数值处理的速度却非常慢。 编辑:我刚刚想到的其他事情:如上所实现,我认为您会制作其他不必要的副本。如果
的长度为
,那么最好将其分配为
的返回值,而不是将其分配给某个子数组(一般情况下必须是副本)。所以:
而不是:
但是,在计时了之后,第一种情况并不会导致速度显着提高(仅约2%),因此可能不必担心太多。我想绝大多数时间是花在生成随机数上(这是我期望的)。
磋判粗惊
涵盖了
的所有可能值(我假设
(即
是错字)),您可以使用:
这个变体比@hgomersall的变体快8倍:
如果
不是错字,而您确实需要
,则:
注意:如果数组的dtype已经是
,则
不会复制。
强制其解释为未签名(也不执行任何复制)。
距相镭
那么您的用法是:
Numpy使用确定性随机数生成(序列中的下一个数字始终相同,初始化时它只是在随机位置开始)。如果您需要真正的随机数据(加密级别),则可以使用
和
代替np。 另外,如果您的BLOCK_SIZE是已定义的常量,则可以使用这样的生成器表达式(这次使用Crypto库):
其中包括实施“ 34”和执行。即使生成器方法的Crypto.Random稍微慢一点,它也会在使计算最大化之前很久就从磁盘i / o最大化(尽管我确定其他答案也是如此)。 更新: Athlon X2 245上的一些计时数据- 加密:生成500MB,不写-10.8s(46 MB / s) 加密:生成500MB并写入-11.2s(44.5 MB / s) numpy:生成500MB,不写入-1.4秒(360 MB /秒) numpy:产生500MB,然后写入-7.1s(70 MB / s) 因此,numpy版本的速度大约快8倍(足够快以使我的旧磁盘驱动器最大化)。我使用生成器表达式形式而不是生成器函数形式测试了它们两者。
盛虱