2009-12-06 68 views
3

將只保留數字數據的記錄轉換爲固定格式字符串並將它們寫入Python文件中的最快方式是什麼?例如,假設record是一個包含屬性爲id,x,ywt的對象的巨大列表,我們經常需要將它們刷新到外部文件。沖洗可以用下面的代碼片段來完成:將數值數據快速轉換爲Python中的固定寬度格式文件

with open(serial_fname(), "w") as f: 
    for r in records: 
     f.write("%07d %11.5e %11.5e %7.5f\n" % (r.id, r.x, r.y, r.wt)) 

但是我的代碼是花費了太多的時間產生外部文件中留下太少時間做什麼是應該的沖洗之間的事。

Amendmend原來的問題:

我就遇到了這個問題,同時編寫跟蹤拉幾個「生產者」系統信息設置一個全球性的記錄,並轉發到任何更改的服務器軟件以預處理的形式實時或接近實時地記錄到「消費者」系統。許多消費者系統都是Matlab應用程序。

我在下面列出了一些建議,我有一些評論到目前爲止(感謝)獲得:

  • 只輸出變化,而不是整個數據集:我其實已經在做。由此產生的變化集仍然很大。
  • 使用二進制(或其他一些更有效的)文件格式:我幾乎由什麼Matlab的能合理高效,除了該格式應該是獨立於平臺的讀取限制。
  • 使用數據庫:我實際上試圖繞過當前的數據庫解決方案,它被認爲既緩慢又麻煩,尤其是在Matlab方面。
  • 將任務劃分爲單獨的進程:目前轉儲代碼正在其自己的線程中運行。但是由於GIL,它仍然在使用相同的核心。我想我可以把它移到完全獨立的進程。

回答

0

您可以嘗試在內存中構建所有輸出字符串,例如使用長字符串。 ,然後在文件中寫入這個長字符串。

更快: 您可能想使用二進制文件而不是文本文件來記錄信息。但是,那麼你需要編寫另一個工具來查看二進制文件。

2

我沒有看到任何關於您可以真正優化的代碼段。所以,我認爲我們需要做一些完全不同的事情來解決你的問題。

你的問題似乎是你正在咀嚼大量數據,並且將數據格式化爲字符串並將字符串寫入文件的速度很慢。你說「沖洗」,這意味着你需要定期保存數據。

您是否經常保存的數據或僅更改了數據?如果你正在處理一個非常大的數據集,改變一些數據,並寫出所有的數據......這是一個我們可以攻擊的角度來解決你的問題。

如果你有一個大的數據集,並且你想不時地更新它......你是一個數據庫的候選人。一個真正的數據庫,用C編寫的速度,可以讓你在它上面扔大量的數據更新,並保持所有的記錄處於一致的狀態。然後你可以每隔一段時間運行一個「報告」,它將拉動記錄並從中寫入固定寬度的文本文件。

換句話說,我建議您將問題分爲兩部分:在您計算或接收更多數據時逐漸更新數據集,並將整個數據集轉儲爲固定寬度的文本格式,以供您進一步研究處理。

請注意,您實際上可以從數據庫生成文本文件,而無需停止正在更新它的Python進程。你會得到一個不完整的快照,但如果記錄是獨立的,那應該沒問題。

如果你的進一步處理也是在Python中,你可以永遠留在數據庫中的數據。不要打擾通過固定寬度的文本文件來回轉數據。我假設你使用的是固定寬度的文本文件,因爲很容易再次提取數據以供將來處理。

如果您使用數據庫的想法,請嘗試使用PostgreSQL。它是免費的,它是一個真正的數據庫。爲了在Python中使用數據庫,您應該使用ORM。最好的之一是SqlAlchemy。

另一件需要考慮的事情是:如果您將數據保存爲固定寬度的文本文件格式,以便將來解析和使用其他應用程序中的數據,並且該應用程序可以讀取JSON以及固定寬度,你可以使用一個寫JSON的C模塊。它可能不會更快,但它可能;你可以通過基準測試來看看。

除了上述內容,我唯一的想法是將程序拆分爲「工作」部分和「更新程序」部分,其中工作人員生成更新記錄,更新程序部分將記錄保存到磁盤。或許讓他們通過讓工作人員以文本格式將更新的記錄放到標準輸出中進行交流;並使更新程序從標準輸入讀取並更新其數據記錄。更新程序可以使用字典來存儲文本記錄,而不是SQL數據庫;當新的到達時,它可以簡單地更新字典。這樣的事情:

for line in sys.stdin: 
    id = line[:7] # fixed width: id is 7 wide 
    records[id] = line # will insert or update as needed 

你實際上可以讓updater保留兩個字典,並保持更新一個,而另一個寫出到磁盤。

劃分爲工作者和更新者是確保工作人員不會花費全部時間更新的好方法,也是平衡跨多個CPU核心工作的好方法。

我現在沒有想法。

0

現在你已經更新了你的問題,我對你面臨的問題有了一個更好的想法。

我不知道「當前的數據庫解決方案既慢又笨」,但我仍認爲如果正確使用數據庫將會有所幫助。

運行Python代碼來收集數據,並使用ORM模塊將數據插入/更新到數據庫中。然後運行一個單獨的進程來創建一個「報告」,這將是固定寬度的文本文件。數據庫會做全部生成你的文本文件的工作。如果有必要,將數據庫放在自己的服務器上,因爲現在硬件相當便宜。

3

我是想檢查是否numpy.savetxt可能加速了一點東西,所以我寫了下面的仿真:

import sys 
import numpy as np 

fmt = '%7.0f %11.5e %11.5e %7.5f' 
records = 10000 

np.random.seed(1234) 
aray = np.random.rand(records, 4) 

def writ(f, aray=aray, fmt=fmt): 
    fw = f.write 
    for row in aray: 
    fw(fmt % tuple(row)) 

def prin(f, aray=aray, fmt=fmt): 
    for row in aray: 
    print>>f, fmt % tuple(row) 

def stxt(f, aray=aray, fmt=fmt): 
    np.savetxt(f, aray, fmt) 

nul = open('/dev/null', 'w') 
def tonul(func, nul=nul): 
    func(nul) 

def main(): 
    print 'looping:' 
    loop(sys.stdout, aray) 
    print 'savetxt:' 
    savetxt(sys.stdout, aray) 

我發現的結果(在我的2.4 GHz的Core Duo處理器的MacBook Pro,與Mac OS X 10.5 2.8,Python的2.5.4從DMG上python.org,numpy的1.4 RC1來源建)略微令人吃驚,但他們具有相當的可重複的,所以我認爲他們可能感興趣的:

$ py25 -mtimeit -s'import ft' 'ft.tonul(ft.writ)' 
10 loops, best of 3: 101 msec per loop 
$ py25 -mtimeit -s'import ft' 'ft.tonul(ft.prin)' 
10 loops, best of 3: 98.3 msec per loop 
$ py25 -mtimeit -s'import ft' 'ft.tonul(ft.stxt)' 
10 loops, best of 3: 104 msec per loop 

如此,savetxt似乎是幾個百分點較慢比一個循環調用write ...但好老print(也在一個循環中)似乎是幾個百分點更快write(我想這是避免某種調用開銷)。我意識到2.5%左右的差距並不是很重要,但它不是我直覺上預期的方向,所以我想我會報告它。 (順便說一句,使用真正的文件,而不是/dev/null只能統一增加6或7毫秒,所以它不會改變很多,這種或那種方式)。

0

你可以嘗試使用ctypes將你的循環推向C語言。

相關問題