我正在測試幾種不同方式的速度來對我的一些數據執行復雜的迭代,並且發現了一些奇怪的東西。似乎有一個本地大的列表功能會大大減慢該功能,即使它沒有觸及該列表。例如,通過相同發生器函數的兩個實例創建2個獨立列表的次數大約是第二次減慢的2.5倍。如果在創建第二個列表之前刪除第一個列表,則兩個迭代器都以相同的速度進行。Python函數因大列表的存在而變慢
def f():
l1, l2 = [], []
for c1, c2 in generatorFxn():
l1.append((c1, c2))
# destroying l1 here fixes the problem
for c3, c4 in generatorFxn():
l2.append((c3, c4))
這些清單最終每件約有310萬件物品,但我也看到了與小清單相同的效果。第一個for
循環需要約4.5秒運行,第二個需要10.5。如果我在評論位置插入l1= []
或l1= len(l1)
,則兩個for
循環都需要4.5秒。
爲什麼函數中局部內存分配的速度與該函數變量的當前大小有什麼關係?
編輯: 禁用垃圾收集器修復了一切,所以必須由於它不斷運行。案件結案!
正確的你是先生,禁用它會下降4.5秒到1.3秒,並幾乎消除了差異(第二個仍然稍微慢一點,但不再多)。爲什麼垃圾收集器運行得如此緩慢,即使在創建一個大型列表之後,它仍然存在,沒有被修改?一旦函數返回,它不應該只有工作嗎? – DaveTheScientist 2011-04-28 19:50:10
另外,如果'l'是一個類變量而不是局部變量,爲什麼減速會消失? – DaveTheScientist 2011-04-28 19:53:12
下面是我最好的猜測:垃圾收集器定期運行以收集舊對象。它通過比較自上次收集以來分配和釋放對象的數量來確定何時運行。如果分配 - 取消分配>閾值,則收集器運行(默認情況下閾值= 700)。由於每次迭代創建(至少)1個新對象,收集器運行3e6/700 = 4285次。這實際上減慢了兩次迭代的速度,但第二次迭代速度較慢,因爲收集器需要檢查更多的對象。 – Luke 2011-04-29 01:25:01