<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                # 7.4。關于發電機的注意事項 > 原文: [http://numba.pydata.org/numba-doc/latest/developer/generators.html](http://numba.pydata.org/numba-doc/latest/developer/generators.html) Numba 最近獲得了編譯發電機功能的支持。本文檔解釋了一些實現選擇。 ## 7.4.1。術語 為清楚起見,我們區分 _ 發生器功能 _ 和 _ 發生器 _。生成器函數是包含一個或多個`yield`語句的函數。生成器(有時也稱為“生成器迭代器”)是生成器函數的返回值;每次調用 [`next()`](https://docs.python.org/3/library/functions.html#next "(in Python v3.7)") 時,它會在其幀內恢復執行。 _ 屈服點 _ 是調用`yield`語句的地方。 _ 恢復點 _ 就在 _ 屈服點 _ 之后的位置,其中當再次調用 [`next()`](https://docs.python.org/3/library/functions.html#next "(in Python v3.7)") 時恢復執行。 ## 7.4.2。功能分析 假設我們有以下簡單的生成器函數: ```py def gen(x, y): yield x + y yield x - y ``` 這是它的 CPython 字節碼,使用 [`dis.dis()`](https://docs.python.org/3/library/dis.html#dis.dis "(in Python v3.7)") 打印出來: ```py 7 0 LOAD_FAST 0 (x) 3 LOAD_FAST 1 (y) 6 BINARY_ADD 7 YIELD_VALUE 8 POP_TOP 8 9 LOAD_FAST 0 (x) 12 LOAD_FAST 1 (y) 15 BINARY_SUBTRACT 16 YIELD_VALUE 17 POP_TOP 18 LOAD_CONST 0 (None) 21 RETURN_VALUE ``` 在 [`NUMBA_DUMP_IR`](../reference/envvars.html#envvar-NUMBA_DUMP_IR) 設置為 1 的情況下編譯此功能時,將打印出以下信息: ```py ----------------------------------IR DUMP: gen---------------------------------- label 0: x = arg(0, name=x) ['x'] y = arg(1, name=y) ['y'] $0.3 = x + y ['$0.3', 'x', 'y'] $0.4 = yield $0.3 ['$0.3', '$0.4'] del $0.4 [] del $0.3 [] $0.7 = x - y ['$0.7', 'x', 'y'] del y [] del x [] $0.8 = yield $0.7 ['$0.7', '$0.8'] del $0.8 [] del $0.7 [] $const0.9 = const(NoneType, None) ['$const0.9'] $0.10 = cast(value=$const0.9) ['$0.10', '$const0.9'] del $const0.9 [] return $0.10 ['$0.10'] ------------------------------GENERATOR INFO: gen------------------------------- generator state variables: ['$0.3', '$0.7', 'x', 'y'] yield point #1: live variables = ['x', 'y'], weak live variables = ['$0.3'] yield point #2: live variables = [], weak live variables = ['$0.7'] ``` 這是什么意思?第一部分是 Numba IR,如[第 2 階段:生成 Numba IR](architecture.html#arch-generate-numba-ir) 所見。我們可以看到兩個屈服點(`yield $0.3`和`yield $0.7`)。 第二部分顯示了特定于發電機的信息。要理解它,我們必須了解暫停和恢復生成器的含義。 掛起生成器時,我們不僅僅向調用者返回一個值(`yield`語句的操作數)。我們還必須保存發生器的 _ 當前狀態 _ 以便恢復執行。在簡單的用例中,可能會保留 CPU 的寄存器值或堆棧槽,直到下一次調用 next()。但是,任何非平凡的案例都會無可救藥地破壞這些價值觀,因此我們必須將它們保存在一個定義明確的地方。 我們需要保存哪些值?那么,在 Numba Intermediate Representation 的背景下,我們必須在每個屈服點保存所有 _ 實時變量 _。由于控制流程圖,計算了這些實時變量。 保存實時變量并暫停生成器后,恢復生成器只需執行逆操作:實時變量將從保存的生成器狀態恢復。 注意 這是相同的分析,有助于在適當的地方插入 Numba `del`指令。 讓我們再次查看生成器信息: ```py generator state variables: ['$0.3', '$0.7', 'x', 'y'] yield point #1: live variables = ['x', 'y'], weak live variables = ['$0.3'] yield point #2: live variables = [], weak live variables = ['$0.7'] ``` Numba 計算了所有實時變量的并集(表示為“狀態變量”)。這將有助于定義[發生器結構](#generator-structure)的布局。此外,對于每個屈服點,我們計算了兩組變量: * _ 實時變量 _ 是恢復點之后的代碼使用的變量(即在`yield`語句之后) * _ 弱活變量 _ 是在恢復點之后立即進行定義的變量;它們必須保存在[對象模式](../glossary.html#term-object-mode)中,以確保正確的參考清理 ## 7.4.3。發電機結構 ### 7.4.3.1。布局 功能分析有助于我們收集足夠的信息來定義生成器結構的布局,該布局將存儲生成器的整個執行狀態。這是生成器結構布局的草圖,用偽代碼表示: ```py struct gen_struct_t { int32_t resume_index; struct gen_args_t { arg_0_t arg0; arg_1_t arg1; ... arg_N_t argN; } struct gen_state_t { state_0_t state_var0; state_1_t state_var1; ... state_N_t state_varN; } } ``` 讓我們按順序描述這些字段。 * 第一個成員 _ 恢復索引 _ 是一個整數,告訴生成器必須恢復恢復點執行。按照慣例,它可以有兩個特殊值:0 表示執行必須從生成器的開頭開始(即第一次調用 [`next()`](https://docs.python.org/3/library/functions.html#next "(in Python v3.7)") ); -1 表示生成器已耗盡,并且恢復必須立即引發 StopIteration。其他值表示屈服點的指數從 1 開始(對應于上面的發電機信息中顯示的指數)。 * 第二個成員,_ 參數結構 _ 在首次初始化后是只讀的。它存儲調用生成器函數的參數的值。在我們的例子中,這些是`x`和`y`的值。 * 第三個成員,_ 狀態結構 _,存儲如上計算的實時變量。 具體來說,我們的示例的生成器結構(假設生成器函數使用浮點數調用)是: ```py struct gen_struct_t { int32_t resume_index; struct gen_args_t { double arg0; double arg1; } struct gen_state_t { double $0.3; double $0.7; double x; double y; } } ``` 請注意,此處保存`x`和`y`是多余的:Numba 無法識別狀態變量`x`和`y`與`arg0`和`arg1`具有相同的值。 ### 7.4.3.2。分配 Numba 如何確保發電機結構保持足夠長的時間?有兩種情況: * 當從 Numba 編譯的函數調用 Numba 編譯的生成器函數時,該結構由被調用者在堆棧上分配。在這種情況下,發電機實例化實際上是無成本的。 * 當從常規 Python 代碼調用 Numba 編譯的生成器函數時,實例化 CPython 兼容的包裝器,其具有適當的分配空間來存儲結構,并且其 [`tp_iternext`](https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_iternext "(in Python v3.7)") 插槽是一個包裝器生成器的本機代碼。 ## 7.4.4。編譯為本機代碼 在編譯生成器函數時,Numba 實際生成了三個本機函數: * 初始化函數。這是與生成器函數本身對應的函數:它接收函數參數并將它們存儲在生成器結構(由指針傳遞)中。它還將 _ 恢復指數 _ 初始化為 0,表明發電機尚未啟動。 * next()函數。這是在生成器內恢復執行的函數。它的單個參數是指向生成器結構的指針,它返回下一個產生的值(如果生成器耗盡,則使用特殊的退出代碼,以便在從 Numba 編譯的函數調用時進行快速檢查)。 * 可選的終結器。在對象模式下,此功能可確保存儲在生成器狀態中的所有實時變量都被減少,即使生成器在沒有耗盡的情況下被銷毀也是如此。 ### 7.4.4.1。 next()函數 next()函數是三個本機函數中最不直接的函數。它以蹦床開始,根據存儲在發生器結構中的 _ 恢復索引 _,將執行分配到右恢復點。以下是函數 start 在我們的示例中的外觀: ```py define i32 @"__main__.gen.next"( double* nocapture %retptr, { i8*, i32 }** nocapture readnone %excinfo, i8* nocapture readnone %env, { i32, { double, double }, { double, double, double, double } }* nocapture %arg.gen) { entry: %gen.resume_index = getelementptr { i32, { double, double }, { double, double, double, double } }* %arg.gen, i64 0, i32 0 %.47 = load i32* %gen.resume_index, align 4 switch i32 %.47, label %stop_iteration [ i32 0, label %B0 i32 1, label %generator_resume1 i32 2, label %generator_resume2 ] ; rest of the function snipped ``` (從 LLVM IR 修剪的無趣的東西,使其更具可讀性) 我們在`%arg.gen`中識別出指向生成器結構的指針。蹦床開關有三個目標(每個 _ 恢復指數 _ 0,1 和 2),以及一個名為`stop_iteration`的后退目標標簽。標簽`B0`表示函數的開始,`generator_resume1`(相應`generator_resume2`)是第一個(相應的第二個)屈服點之后的恢復點。 在 LLVM 生成之后,此函數的整個本機匯編程序代碼可能如下所示(在 x86-64 上): ```py .globl __main__.gen.next .align 16, 0x90 __main__.gen.next: movl (%rcx), %eax cmpl $2, %eax je .LBB1_5 cmpl $1, %eax jne .LBB1_2 movsd 40(%rcx), %xmm0 subsd 48(%rcx), %xmm0 movl $2, (%rcx) movsd %xmm0, (%rdi) xorl %eax, %eax retq .LBB1_5: movl $-1, (%rcx) jmp .LBB1_6 .LBB1_2: testl %eax, %eax jne .LBB1_6 movsd 8(%rcx), %xmm0 movsd 16(%rcx), %xmm1 movaps %xmm0, %xmm2 addsd %xmm1, %xmm2 movsd %xmm1, 48(%rcx) movsd %xmm0, 40(%rcx) movl $1, (%rcx) movsd %xmm2, (%rdi) xorl %eax, %eax retq .LBB1_6: movl $-3, %eax retq ``` 注意,函數返回 0 表示產生一個值,-3 表示 StopIteration。 `%rcx`指向生成恢復索引的生成器結構的開始。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看