簡體   English   中英

為什么直接索引數組比迭代快得多?

[英]Why is direct indexing of an array significantly faster than iteration?

僅提供一些Python代碼作為示例:

nums = [1,2,3]
start = timer()
for i in range(len(nums)):
  print(nums[i])
end = timer()

print((end-start)) #computed to 0.0697546862831


start = timer()
print(nums[0])
print(nums[1])
print(nums[2])
end = timer()

print((end-start)) #computed to 0.0167170338524

我可以理解,因為i的值必須增加幾次,所以循環會花費一些額外的時間,但是這兩種不同方法的運行時間之間的差異似乎比我預期的要大得多。 引擎蓋下是否還有其他我沒有考慮的事情?

簡短的答案:除非循環非常小,否則不會。 for循環的開銷很小,但是您這樣做的效率很低。 通過使用range(len(nums))您可以有效地創建另一個列表並對其進行迭代,然后無論如何都要進行相同的索引查找。 嘗試這個:

for i in nums:
    print(i)

對我而言,結果符合預期:

>>> import timeit
>>> timeit.timeit('nums[0];nums[1];nums[2]', setup='nums = [1,2,3]')
0.10711812973022461
>>> timeit.timeit('for i in nums:pass', setup='nums = [1,2,3]')
0.13474011421203613
>>> timeit.timeit('for i in range(len(nums)):pass', setup='nums = [1,2,3]')
0.42371487617492676

列表越大,循環的優勢就越明顯,因為按索引訪問元素的增量成本超過了循環的一次性成本:

>>> timeit.timeit('for i in nums:pass', setup='nums = range(0,100)')
1.541944980621338
timeit.timeit(';'.join('nums[%s]' % i for i in range(0,100)), setup='nums = range(0,100)')
2.5244338512420654

在python 3中,它更加着重於可索引列表上的迭代器,兩者的區別甚至更大:

>>> timeit.timeit('for i in nums:pass', setup='nums = range(0,100)')
1.6542046590038808
>>> timeit.timeit(';'.join('nums[%s]' % i for i in range(0,100)), setup='nums = range(0,100)')
10.331634456000756

使用如此小的數組,您可能首先要測量噪聲,然后再測量range()的開銷。 請注意, range不僅必須增加變量幾次,而且還因為它是生成器而創建了一個保存其狀態(當前值)的對象。 函數調用和對象創建是您在第二個示例中無需支付的兩件事,對於非常短的迭代,它們可能會使三個數組訪問相形見war。

本質上,您的第二個代碼片段確實會循環展開 ,這是一種提高性能關鍵代碼的可行且頻繁的技術。

在任何情況下, for loop產生成本,並且您編寫的for loop特別昂貴。 這是四個版本,使用timeit來度量時間:

from timeit import timeit

NUMS = [1, 2, 3]


def one():
    for i in range(len(NUMS)):
          NUMS[i]


def one_no_access():
    for i in range(len(NUMS)):
          i


def two():
    NUMS[0]
    NUMS[1]
    NUMS[2]


def three():
    for i in NUMS:
        i


for func in (one, one_no_access, two, three):
    print(func.__name__ + ':', timeit(func))

這是找到的時間:

one: 1.0467438200000743
one_no_access: 0.8853238560000136
two: 0.3143197629999577
three: 0.3478466749998006

one_no_access顯示表達式range(len(NUMS))的開銷。 雖然python中的列表連續存儲在內存中,但是元素的隨機訪問位於O(1) ,這兩個元素的解釋速度更快。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM