现在,我正在尝试将纬度经度高度格式的大量二进制文件转换为基于文本的ECEF笛卡尔格式(x,y,z)。现在的问题是这个过程非常非常缓慢。
我有超过100 GB的这些东西要运行,可能会有更多的数据进入。我想尽可能快地编写这段代码。
现在我的代码看起来像这样:
import mmap
import sys
import struct
import time
pointSize = 41
def getArguments():
if len(sys.argv) != 2:
print """Not enough arguments.
example:
python tllargbin_reader.py input_filename.tllargbin output_filename
"""
return None
else:
return sys.argv
print getArguments()
def read_tllargbin(filename, outputCallback):
f = open(filename, "r+")
map = mmap.mmap(f.fileno(),0)
t = time.clock()
if (map.size() % pointSize) != 0:
print "File size not aligned."
#return
for i in xrange(0,map.size(),pointSize):
data_list = struct.unpack('=4d9B',map[i:i+pointSize])
writeStr = formatString(data_list)
if i % (41*1000) == 0:
print "%d/%d points processed" % (i,map.size())
print "Time elapsed: %f" % (time.clock() - t)
map.close()
def generate_write_xyz(filename):
f = open(filename, 'w', 128*1024)
def write_xyz(writeStr):
f.write(writeStr)
return write_xyz
def formatString(data_list):
return "%f %f %f" % (data_list[1], data_list[2],data_list[3])
args = getArguments()
if args != None:
read_tllargbin(args[1],generate_write_xyz("out.xyz"))
convertXYZ()基本上就是这里的转换公式: http://en.wikipedia.org/wiki/Geodetic_system
我想知道用一个线程读取大约4MB的块,将它们放在有限的缓冲区中,使用不同的线程转换为字符串格式,并让最后一个线程将字符串写回到另一个硬盘上的文件。我可能会跳枪......
我现在正在使用python进行测试,但如果我能更快地处理这些文件,我不会反对切换。
任何建议都会很棒。感谢
修改
我已经用cProfile再次分析了代码,这次分割了字符串格式和io。看来我实际上是被字符串格式杀死了......这是分析器报告
20010155 function calls in 548.993 CPU seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 548.993 548.993 <string>:1(<module>)
1 0.016 0.016 548.991 548.991 tllargbin_reader.py:1(<module>)
1 24.018 24.018 548.955 548.955 tllargbin_reader.py:20(read_tllargbin)
1 0.000 0.000 0.020 0.020 tllargbin_reader.py:36(generate_write_xyz)
10000068 517.233 0.000 517.233 0.000 tllargbin_reader.py:42(formatString)
2 0.000 0.000 0.000 0.000 tllargbin_reader.py:8(getArguments)
10000068 6.684 0.000 6.684 0.000 {_struct.unpack}
1 0.002 0.002 548.993 548.993 {execfile}
2 0.000 0.000 0.000 0.000 {len}
1 0.065 0.065 0.065 0.065 {method 'close' of 'mmap.mmap' objects}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
1 0.000 0.000 0.000 0.000 {method 'fileno' of 'file' objects}
10003 0.955 0.000 0.955 0.000 {method 'size' of 'mmap.mmap' objects}
2 0.020 0.010 0.020 0.010 {open}
2 0.000 0.000 0.000 0.000 {time.clock}
是否有更快的格式化字符串的方式?
答案 0 :(得分:2)
为了更准确地解决问题,我建议通过使'convertXYZ'成为无操作函数并对结果进行计时来测量文件读取操作。并测量转换函数,通过更改“读取”以始终返回一个简单的点,但调用转换并输出相同的次数,就像您真正读取文件一样。 (可能是另一个最终转换后输出为无操作的运行。)根据时间的推移,攻击其中一个可能更有意义。
您可以通过将输出写入Python的stdout并让shell执行实际的文件IO,让本地操作系统为您做一些交错。类似地,通过将文件流式传输到标准输入(例如,cat oldformat | python conversion.py > outputfile
)
输入和输出文件是什么类型的存储?与Python代码相比,存储特性可能与性能有很大关系。
更新:鉴于输出速度最慢,并且您的存储速度非常慢并且在读取和写入之间共享,请尝试添加一些缓冲。从the python doc开始,您应该可以通过向os.open
调用添加第三个参数来添加一些缓冲。尝试像128 * 1024那样大的东西吗?
答案 1 :(得分:0)
鉴于formatString
是最慢的操作,请尝试:
def formatString(data_list):
return " ".join((str(data_list[1]), str(data_list[2]), str(data_list[3])))
答案 2 :(得分:0)
2.1 GB的数据应该在21(@ 100 MB / s)到70(@ 30 MB / s)秒之间读取。然后,您可以将其格式化为和写入数据,这可能是数据量的五倍。这意味着总共13 GB的读写需要130-420秒。
您的抽样显示阅读需要24秒。因此,写作需要大约两分钟。例如,使用SSD可以改善读写时间。
当我转换文件时(使用我在C中编写的程序),我认为转换不应该花费更多的时间来读取数据本身,通常可以少得多。重叠的读写操作也可以减少I / O时间。我编写自己的自定义格式化例程,因为printf通常太慢了。
24秒多少钱?在现代CPU上至少有40亿条指令。这意味着在那段时间内,您可以使用至少19条指令处理每个字节的数据。可以轻松地用于C程序,但不能用于解释性语言(Python,Java,C#,VB)。
你的525秒处理(549-24)余数表明Python每个字节的数据读取至少花费了875亿条指令处理或415条指令。结果是22比1:解释和编译语言之间的比例并不罕见。一个结构良好的C程序每个字节或更少的数据应该减少十个指令。