Python生成千万行的文本并测试numpy运算性能

Python生成千万行的浮点数文本文件
测试numpy运算性能


生成千万行的浮点数文本文件,浮点数范围从0到1之间,Python代码:

from random import random
from array import array
with open('/Users/molock/floats-10M-lines.txt', 'w') as f:
l = [str(random()) for i in range(10**7)]
f.write('\n'.join(l))

以上代码用Python3.5运行,在本机(i5的mbp)运行需要13、14秒。

生成的文本文件floats-10M-lines.txt大小是192701137字节,约192.7MB。

用numpy加载文本,简单测试加减乘除的性能。

perf_counter是Python3的计时器模块time下入精度和性能都比较高的计时器。(Python 3.3 及更新的版本中都有这个库)

用这个计时器来估算性能。

测试代码:

import numpy
from time import perf_counter as pc
t_load = pc()
floats = numpy.loadtxt('/Users/molock/floats-10M-lines.txt')
print("load data time:", pc() - t_load)
print(floats[-3:]) # 查看最后三个数
t_add = pc()
floats += .5
print("add time:", pc() - t_add)
print(floats[-3:])
t_minus = pc()
floats -= .4
print("minus time:", pc() - t_minus)
print(floats[-3:])
t_mul = pc()
floats *= 2.79
print("multiply time:", pc() - t_mul)
print(floats[-3:])
t_div = pc()
floats /= 3.52
print("division time:", pc() - t_div)
print(floats[-3:])
t_save = pc()
# 将运算后的结果floats数组存入后缀为.npy的二进制文件
numpy.save('/Users/molock/floats-10M', floats)
print("save data time:", pc() - t_save)
t_load_again = pc()
floats2 = numpy.load('/Users/molock/floats-10M.npy', 'r+')
print("load data again time:", pc() - t_load_again)
print(floats2[-3:])

numpy.load 方法利用了一种叫作内存映射的机制,它让我们在内存不足的情况下仍然可以对数组做切片。

输出结果:

load data time: 65.7026106659323
[ 0.96038447 0.99720327 0.39896402]
add time: 0.017584401881322265
[ 1.46038447 1.49720327 0.89896402]
minus time: 0.0120230030734092
[ 1.06038447 1.09720327 0.49896402]
multiply time: 0.008878643857315183
[ 2.95847266 3.06119711 1.39210962]
division time: 0.01236245408654213
[ 0.84047519 0.86965827 0.39548569]
save data time: 0.07357809785753489
load data again time: 0.11263397801667452
[ 0.84047519 0.86965827 0.39548569]
[Finished in 66.6s]

结果分析:

numpy.loadtxt加载文本文件生成数组并不快,1000万行,192.7M的文件load时间超过1分钟(65.7秒),相比之下代码生成文本文件的时间是13、14秒,大概是5倍。慢的原因是:从文本文件里读取时,会使用内置的 float 方法把每一行文字转换成浮点数。

numpy数组的加减乘除是很高效的,1000万个浮点数的加减乘除分别都在18毫秒内完成了。

numpy数组保存为二进制文件效率很高,只需要73毫秒。二进制文件大小为80M(一个float数字8字节,1000万个)。

把二进制文件load进来效率也很高,只需要112毫秒。相同的行数,load文本文件的时间是65秒,大概是load二进制文件的580倍。

总结:

  • 二进制文件的读取比文本文件的读取高效得多,占用内存也小得多。
  • numpy运算的高性能可见一斑。