2011-10-19 30 views
1

現在,我試圖將緯度經度高度格式的大量二進制文件轉換爲基於文本的ECEF笛卡爾格式(x,y,z)。現在的問題是這個過程非常非常緩慢。大(2.1gb +)二進制文件(緯度/長度/高度到ECEF)的快速轉換

我有超過100千兆字節的這些東西來運行,更多的數據可能會進來。我想盡可能快地使這一點的代碼。

現在我的代碼看起來是這樣的:

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}    

有沒有更快的格式化字符串的方法?

+1

你是否分析了代碼以找出哪些部分很慢? – Daenyth

+0

如果你的辦公室裏有幾臺電腦沒有做任何事情,也許你可以考慮hadoop? http://www.michael-noll.com/tutorials/writing-an-hadoop-mapreduce-program-in-python/希望它不會必須通過 –

+0

如果將'write'調用改爲' f.write(「some_string_of_about_the_length_of_your_numbers」)'所以你可以看到有多少時間是字符串格式? – agf

回答

2

爲了更準確地解決問題,我建議通過將'convertXYZ'設爲無操作函數並對結果進行計時來測量文件讀取操作。並測量轉換函數,通過改變'讀'總是返回一個簡單的點,但調用轉換和輸出相同的次數,如果你真的讀文件。 (可能是另一個運行的地方,最終的轉換後輸出是空操作。)根據時間的推移,它可能會更有意義地攻擊一個或另一個。

您可以通過將輸出寫入Python的stdout並讓shell執行實際的文件IO來讓本地操作系統爲您執行一些交叉操作。類似地,將文件流式傳輸到標準輸入(例如,cat oldformat | python conversion.py > outputfile

輸入和輸出文件是什麼類型的存儲?與Python代碼相比,存儲特性對性能的影響可能更多。

更新:鑑於輸出是最慢的,並且您的存儲非常緩慢並且在讀取和寫入之間共享,請嘗試添加一些緩衝。從the python doc你應該能夠通過在os.open調用中添加第三個參數來添加一些緩衝。試試像128 * 1024那麼大的東西?

+0

嗨,謝謝你的回覆。 我實際上已經將convertXYZ作爲noOp(它只是返回前三個雙精度),在一個小的400MB文件上,它每個文件大約運行10分鐘,或者大約682.666667 kBps。存儲格式是普通的7200 RPM內部SATA2驅動器 – Xzhsh

+0

我再次檢查了分析器,並將寫入函數分成了字符串格式和寫入,似乎我實際上被字符串格式殺死了......是否有更快的方法來執行它? – Xzhsh

+0

哇,我在本地重現格式是慢的,我不確定是否它的格式化或新字符串alloc-and-GC殺死了這個,我沒有看到任何像Java的'StringBuffer'這樣的Python幫助隔離GC效應值得問一個更專注的SO問題(或者嘗試用Perl或Java或C重寫它) –

0

鑑於formatString是最慢的操作,試試這個:

def formatString(data_list): 
    return " ".join((str(data_list[1]), str(data_list[2]), str(data_list[3]))) 
+0

嗨,謝謝你的回覆。我對它進行了測試,但它似乎也很慢,即使不比%格式慢。 – Xzhsh

0

2.1 GB的數據,應該採取與21(@ 100 MB /秒)到70(@ 30 MB /秒)秒,剛剛讀。然後,您將這些數據格式化並寫入大概五倍的數據。這意味着總共13 GB的讀寫需要130-420秒。

您的採樣顯示讀數需要24秒。因此寫作需要大約兩分鐘的時間。例如,使用SSD可以提高讀取和寫入時間。

當我轉換文件(使用我用C編寫的程序)時,我認爲轉換不會花費更多的時間來讀取數據本身,通常可能少得多。重疊的讀取和寫入也可以減少I/O時間。我編寫自己的自定義格式化例程,因爲printf通常太慢了。

24秒多少錢?在現代CPU上至少有400億條指令。這意味着在那段時間內,您可以使用至少19條指令處理每一個字節的數據。輕鬆實現C程序,但不適用於解釋型語言(Python,Java,C#,VB)。

剩餘的525次處理(549-24)表明Python正在花費至少875億條指令處理或每字節數據讀取415條指令。這是22比1:解釋語言和編譯語言之間的比例並不少見。一個構造良好的C程序應該每個字節大約減少10條指令或更少。