2016-02-03 33 views
1

StringIO在其代碼如下注意事項:真實文件對象比StringIO和cStringIO慢嗎?

Notes: 
- Using a real file is often faster (but less convenient). 
- There's also a much faster implementation in C, called cStringIO, but 
    it's not subclassable. 

「真正的文件往往是快」線似乎太奇怪了吧:怎麼會在寫入磁盤擊敗寫入內存?我試圖分析這些不同的案例,並得出與這些文檔相矛盾的結果,以及對this question的回答。 This other question解釋了爲什麼cStringIO在某些情況下速度較慢,儘管我在這裏沒有進行任何連接。測試將給定數量的數據寫入文件,然後查找到開始並將其讀回。在「新」測試中,我每次都創建一個新對象,並在「相同」的對象上截斷並重復使用同一對象,以排除這些開銷。這個開銷對使用具有小數據大小但不是大數據的臨時文件很重要。代碼爲here

Using 1000 passes with size 1.0KiB 
New StringIO: 0.0026 0.0025 0.0034 
Same StringIO: 0.0026 0.0023 0.0030 
New cStringIO: 0.0009 0.0010 0.0008 
Same cStringIO: 0.0009 0.0009 0.0009 
New tempfile: 0.0679 0.0554 0.0542 
Same tempfile: 0.0069 0.0064 0.0070 
============================================================== 
Using 1000 passes with size 100.0KiB 
New StringIO: 0.0093 0.0099 0.0108 
Same StringIO: 0.0109 0.0090 0.0086 
New cStringIO: 0.0130 0.0139 0.0120 
Same cStringIO: 0.0118 0.0115 0.0124 
New tempfile: 0.1006 0.0905 0.0899 
Same tempfile: 0.0573 0.0526 0.0523 
============================================================== 
Using 1000 passes with size 1.0MiB 
New StringIO: 0.0727 0.0700 0.0717 
Same StringIO: 0.0740 0.0735 0.0712 
New cStringIO: 0.1484 0.1399 0.1470 
Same cStringIO: 0.1493 0.1393 0.1465 
New tempfile: 0.6576 0.6750 0.6821 
Same tempfile: 0.5951 0.5870 0.5678 
============================================================== 
Using 1000 passes with size 10.0MiB 
New StringIO: 1.0965 1.1129 1.1079 
Same StringIO: 1.1206 1.2979 1.1932 
New cStringIO: 2.2532 2.2162 2.2482 
Same cStringIO: 2.2624 2.2225 2.2377 
New tempfile: 6.8350 6.7924 6.8481 
Same tempfile: 6.8424 7.8114 7.8404 
============================================================== 

兩個StringIO實現是相當具有可比性,雖然cStringIO放緩顯著爲大數據量。但tempfile.TemporaryFile總是花費3倍於最慢的StringIO

+0

我不相信你在這裏比較的是正確的事情。這些答案正在討論你的基本Python文件包裝器 - 「文件」 - 而不是「tempfile.TemporaryFile」。 –

+0

可能是因爲文件IO都被操作系統高度優化,並且通過內存緩存,在一些常見情況下,這些內存緩存可能比不管Python模塊在後臺執行什麼操作都快。 – dtanders

+0

@ Two-BitAlchemist我不希望'TemporaryFile'與'file'有很大的不同,因爲讀寫是不一樣的。看看'tempfile','TemporaryFile'實際上是一個返回'file's的函數,至少在POSIX(這是我使用的)上。任何來自創建差異的開銷都應該由「相同的臨時文件」情況來處理。 –

回答

3

這一切都取決於「經常」的含義。 StringIO通過將您的寫入保持在列表中,然後將列表連接到讀取的字符串來實現。你的測試用例 - 一系列的讀寫操作 - 是它的最佳場景。如果我調整測試用例在文件中執行50次隨機寫入/讀取,則cStringIO傾向於在文件系統中位居第二。

該評論似乎反映了系統程序員的偏見,讓c庫加上操作系統做文件系統的事情,因爲從一般意義上來說很難猜測什麼在所有條件下執行得最好。

def write_and_read_test_data(flo): 
    fsize = len(closure['test_data']) 
    flo.write(closure['test_data']) 
    for _ in range(50): 
     flo.seek(random.randint(0, fsize-1)) 
     flo.write('x') 
     flo.read(1) 
    flo.seek(0) 
    closure['output'] = flo.read() 

的10meg測試用例所花的時間比我的注意力......

Using 1000 passes with size 1.0KiB 
New StringIO: 0.9551 0.9467 0.9366 
Same StringIO: 0.9252 0.9228 0.9207 
New cStringIO: 0.3274 0.3280 0.3251 
Same cStringIO: 0.3182 0.3231 0.3280 
New tempfile: 1.1833 1.1853 1.1650 
Same tempfile: 0.9563 0.9414 0.9504 
============================================================== 
Using 1000 passes with size 100.0KiB 
New StringIO: 5.6253 5.6589 5.6025 
Same StringIO: 5.5799 5.5608 5.5589 
New cStringIO: 0.4157 0.4133 0.4140 
Same cStringIO: 0.4078 0.4076 0.4088 
New tempfile: 2.0420 2.0391 2.0408 
Same tempfile: 1.5722 1.5749 1.5693 
============================================================== 
Using 1000 passes with size 1.0MiB 
New StringIO: 105.2350 106.3904 107.5411 
Same StringIO: 108.3744 109.4510 105.6012 
New cStringIO: 2.4698 2.4781 2.4165 
Same cStringIO: 2.4699 2.4600 2.4451 
New tempfile: 6.6086 6.5783 6.5916 
Same tempfile: 6.1420 6.1614 6.1366 
+0

D'oh!隨機訪問必須使'StringIO'複製大量的數據,因爲它具有不可變字符串的支持。有趣的是:另一個答案聲稱這是由於Python的解釋性質,但它似乎並不是真正的罪魁禍首。我剛剛添加了'_pyio.BytesIO'測試:它是用Python實現的,就像'StringIO'一樣,但是使用了可變的字節數組。它只花了兩倍於'cStringIO'的長度,儘管被解釋,仍然擊敗了'TemporaryFile'。我想我會在其他問題上增加一個答案。謝謝! –