簡體   English   中英

如何盡可能快地制作Python生成器?

[英]How to make Python generators as fast as possible?

對於編寫事件驅動的模擬器,我依賴於simpy ,它大量使用Python生成器。 我試圖了解如何盡可能快地生成生成器,即最小化狀態保存/恢復開銷。 我嘗試了三種選擇

  1. 所有狀態都存儲在類實例中
  2. 全局存儲全部狀態
  3. 所有狀態都存儲在本地

並使用Python 3.4.3獲得以下結果:

class_generator 20.851247710175812
global_generator 12.802394330501556
local_generator 9.067587919533253

代碼可以在這里找到。

這對我來說是違反直覺的:在類實例中存儲所有狀態意味着只需要保存/恢復self ,而全局存儲所有狀態應確保零保存/恢復開銷。

有誰知道為什么類生成器和全局生成器比本地生成器慢?

產量發生時,生成器實際上保留了實際的調用幀 無論您有1個還是100個局部變量,它都不會真正影響性能。

性能差異真的來自Python(這里我使用的是CPython,也就是你從http://www.python.com/下載的那個,或者你的操作系統是/usr/bin/python ,但是由於大多數相同的原因,大多數實現具有類似的性能特征)在不同類型的變量查找上表現:

  • 在Python中實際上沒有命名局部變量; 相反,它們由一個數字引用,並由LOAD_FAST操作碼訪問。

  • 使用LOAD_GLOBAL操作碼訪問全局變量。 它們總是被名稱引用,因此每次訪問都需要實際的字典查找。

  • 實例屬性訪問是最慢的,因為self.foobar首先需要使用LOAD_FAST來加載對self的引用,然后LOAD_ATTR用於在引用的對象上查找foobar ,這是一個字典查找。 此外,如果屬性在實例本身上,這將是正常的,但如果在上設置,則屬性查找將變慢。 您還要在實例上設置值,它會更慢,因為現在它需要在加載的實例上執行STORE_ATTR 更復雜的是,實例的也需要被查詢 - 如果恰好具有相同名稱的屬性描述符 ,那么它可以改變讀取和設置屬性的行為。

因此,最快的生成器是僅引用局部變量的生成器。 Python代碼中常見的習慣用法是將全局只讀變量的值存儲到局部變量中以加快速度。

為了演示差異,請考慮為這3個變量訪問abself.c生成的代碼:

a = 42

class Foo(object):
    def __init__(self):
        self.c = 42

    def foo(self):
        b = 42
        yield a
        yield b
        yield self.c

print(list(Foo().foo()))   # prints [42, 42, 42]

foo方法的反匯編的相關部分是:

  8           6 LOAD_GLOBAL              0 (a)
              9 YIELD_VALUE
             10 POP_TOP

  9          11 LOAD_FAST                1 (b)
             14 YIELD_VALUE
             15 POP_TOP

 10          16 LOAD_FAST                0 (self)
             19 LOAD_ATTR                1 (c)
             22 YIELD_VALUE
             23 POP_TOP

LOAD_GLOBALLOAD_ATTR的操作數LOAD_ATTR是對名稱ac引用; 數字是桌子上的指數。 LOAD_FAST的操作數是局部變量表的局部變量的編號

生成器需要保存的唯一狀態是對堆棧幀的引用,因此無論涉及多少狀態以及放置數據的位置,保存和恢復狀態都會花費完全相同的時間。

您在時間上看到的差異完全取決於Python可以訪問值的速度:本地變量訪問速度非常快,全局變量訪問需要查找全局字典中的值,因此速度較慢,並且類成員訪問需要訪問本地變量'self',然后對該值執行至少一次字典查找(同樣,對類生成器的調用必須轉換為具有單個參數的調用,該參數本身比沒有其他調用的調用慢參數)。

暫無
暫無

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

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