簡體   English   中英

python memoryview比預期的慢

[英]python memoryview slower than expected

鑒於Python的memoryview接口與緩沖的協議可以幫助減少需要進行數據的拷貝臨時,我決定做在此基礎上它的一個快速測試的回答這個問題

import time

expressions = ['list(b[i:i+1000])',
               'list(b[i:])',
               'b[i:]'
              ]

size = 1000000
x = b'x'*size
mv = memoryview(x)
for e in expressions:
    print(f"Expression: {e}")
    for b in (x, mv):
        l = len(b)
        start = time.time()
        for i in range(0, l, 1000):
            eval(e)
        end = time.time()
        print(f"Size: {size}, {type(b).__name__}, time: {end-start}")

結果:

$ python c:\temp\test_memoryview.py
Expression: list(b[i:i+1000])
Size: 1000000, bytes, time: 0.021999597549438477
Size: 1000000, memoryview, time: 0.03600668907165527
Expression: list(b[i:])
Size: 1000000, bytes, time: 5.3010172843933105
Size: 1000000, memoryview, time: 11.202003479003906
Expression: b[i:]
Size: 1000000, bytes, time: 0.2990117073059082
Size: 1000000, memoryview, time: 0.006985902786254883

前兩個結果似乎令人驚訝。 我知道調用列表將涉及數據的副本,但是我認為在切片內存視圖而不是基礎字節數組時,您可以保存臨時副本。

您無法像C或C ++那樣想到Python。 額外副本的常量因子開銷遠低於支持所有Python動態特性所涉及的常量因子開銷,尤其是在CPython中沒有JIT的情況下。 一旦考慮到要避免使用該副本而必須更改的其他內容,您就不能認為保存一個副本實際上會有所幫助。

在這種情況下,幾乎所有工作都在列表轉換中。 您要保存的副本毫無意義。 比較b[i:]list(b[i:]) ,您會發現切片僅占運行時的百分之幾,即使切片執行復制也是如此。

保存的副本無關緊要,因為它基本上只是memcpy 相比之下,列表轉換需要在字節串或memoryview上創建一個迭代器,重復調用迭代器的tp_iternext插槽,獲取與內存的原始字節對應的int對象,等等,這更加昂貴。 對於memoryview來說,這甚至會更加昂貴,因為memoryview對象必須支持多維形狀和非字節數據類型,並且因為memoryview實現沒有專用的__iter__實現,所以它經歷了基於序列的通用后備迭代,比較慢

您可以使用memoryview的tolist方法而不是調用list來節省一些時間。 這樣可以避免一堆迭代協議的開銷,並允許僅執行一次檢查,而不是每個項目一次。 在我的測試中,這幾乎和調用字節串上的list一樣快。

暫無
暫無

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

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