我得到了類似的結果,但沒有這麼戲劇化你的。 (注意使用timeit
模塊代碼執行計時的,請注意,我已經排除,因爲其常見的兩種測試案例列表創建。)
import csv
from timeit import Timer
def write_csv(f, n):
"""Write n records to the file named f."""
w = csv.writer(open(f, 'wb'))
for i in xrange(n):
w.writerow((i, "squared", "equals", i**2))
def test1(rows, f, n):
for i, r in enumerate(csv.reader(open(f))):
rows[i] = r
def test2(rows, f, n):
for i, r in enumerate(csv.reader(open(f))):
pass
def test(t):
return (Timer('test%d(rows, F, N)' % t,
'from __main__ import test%d, F, N; rows = [None] * N' % t)
.timeit(number=1))
>>> N = 1446311
>>> F = "test.csv"
>>> write_csv(F, N)
>>> test(1)
2.2321770191192627
>>> test(2)
1.7048690319061279
這是我的猜測,到底是怎麼回事。在這兩個測試中,CSV閱讀器都從該文件中讀取一條記錄,並在代表該記錄的內存中創建一個數據結構。
在test2
中,沒有存儲記錄,數據結構立即被刪除或更多(在循環的下一次迭代中,row
變量被更新,因此前一記錄的引用計數減少,並且所以內存被回收)。這使得用於上一個記錄的內存可以重複使用:這個內存已經在計算機的虛擬內存表中,並且可能仍然在緩存中,所以它(相對)很快。
在test1
中,每條記錄都必須分配到一個新的內存區域,該區域必須由操作系統分配並複製到緩存中,因此速度相對較慢。
所以時間不被列表分配,而是由內存分配。
這裏有另一對夫婦的那說明這是怎麼回事測試,而不csv
模塊的複雜因素。在test3
中,我們爲每一行創建一個新的100個元素的列表,並存儲它。在test4
中,我們爲每一行創建一個新的100個元素的列表,但我們不存儲它,我們把它扔掉,這樣內存可以在下一次循環時重新使用。
def test3(rows, f, n):
for i in xrange(n):
rows[i] = [i] * 100
def test4(rows, f, n):
for i in xrange(n):
temp = [i] * 100
rows[i] = None
>>> test(3)
9.2103338241577148
>>> test(4)
1.5666921138763428
所以我覺得教訓是,如果你不需要在內存中的所有行存儲在同一時間,不這樣做!如果可以的話,一次只讀一個,逐個處理它們,然後忘記它們,以便Python可以釋放它們。
我看到L5在那裏和不在那裏的運行時間沒有太大的區別。 (不過我不得不僞造csvReader.next()調用,這可能會產生影響)。 – 2011-07-04 11:55:08
正如Gareth解釋的那樣,您沒有爲所有實際行預先分配內存,並且這種分配是花費時間的。如果你不要求所有的行同時在內存中,你可以通過構建你的代碼來使用生成器/生成器表達式來提高性能 –