半天鐘的博客這篇博文講述的python協程是不正式的、寬泛的協程,即通過客戶調用.send(…)方法發送數據或使用yieldfrom結構驅動的生成器函數,而不是asyncio庫采用的定義更為嚴格的協程。前言在事件驅動型編程中,協程常用于離散事件的仿真(在單個線程中使用一個主循環驅動協程執行并發活動)。協程通過顯式自主地把控制權讓步給中央調度程序從而實現了協作式多任務。所以,協程是python事件驅動型框架和協作式多任務的" />

亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

理解“狹義”的 python 協程

系統 1742 0

轉載自我自己的 github 博客 ——> 半天鐘的博客

這篇博文講述的 python 協程是 不正式的、寬泛的協程 ,即通過客戶調用 .send(…) 方法發送數據或使用 yield from 結構驅動的生成器函數, 而不是 asyncio 庫采用的定義更為嚴格的協程。

前言

事件驅動型編程 中,協程常用于離散事件的仿真(在單個線程中使用一個主循環驅動協程執行并發活動)。

協程通過顯式 自主地把控制權讓步給中央調度程序 從而實現了 協作式多任務

所以, 協程是 python 事件驅動型框架和協作式多任務的基礎。

那么,弄明白協程的 進化過程 、基本行為和 高效的使用方式 是很有必要的。

本博文想要解釋清楚 python 協程的基本行為以及如何高效的使用協程。

在閱讀本文之前,你必須要了解 python 中 yield 關鍵字、和生成器的基本概念。如果你還不知道這兩個概念是啥,你可以看我的上一篇博文:淺析 python 迭代器與生成器 或者通過 CSDN 上馮爽朗的博文 簡單了解 yield 關鍵字的使用方法。

從生成器到協程

協程是指一個過程,這個過程與調用方協作,即 根據調用方提供的值 產出相應的值 給調用方。

從協程的定義來看,協程的部分行為和帶有 yield 關鍵字生成器的行為類似,因為調用方可以使用 .next() 方法 讓生產器產出值給調用方。例如,這個斐波那契生成器函數:

            
              
                >>
              
              
                >
              
              
                def
              
              
                fibonacci
              
              
                (
              
              
                )
              
              
                :
              
              
        a
              
                ,
              
               b 
              
                =
              
              
                0
              
              
                ,
              
              
                1
              
              
                while
              
              
                True
              
              
                :
              
              
                yield
              
               a
            a
              
                ,
              
               b 
              
                =
              
               b
              
                ,
              
               a 
              
                +
              
               b

            
          

調用方調用 next()函數可以 獲取它的產出值

            
              
                >>
              
              
                >
              
               f 
              
                =
              
               fibonacci
              
                (
              
              
                )
              
              
                >>
              
              
                >
              
              
                print
              
              
                (
              
              
                next
              
              
                (
              
              f
              
                )
              
              
                )
              
              
                0
              
              
                >>
              
              
                >
              
              
                print
              
              
                (
              
              
                next
              
              
                (
              
              f
              
                )
              
              
                )
              
              
                1
              
            
          

這么看來, 生成器的行為離協程的行為就差一步,即接收調用方提供的值。

在 python 2.5 后 yield 關鍵字就可以在表達式中使用了,而且生成器 API 中增加了 .send(value)方法。 生成器的調用方可以使用 .send(…) 方法給生成器發送數據。

這樣一來生成器就可以接收調用方提供的值了, 其接收的數據會成為 yield 表達式的值。

例一是一個簡單的例子,來說明調用方如何發送數據及生成器如何接受數據。

            
              
                >>
              
              
                >
              
              
                def
              
              
                coroutine
              
              
                (
              
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              
                '-- 協程開始 --'
              
              
                )
              
              
        x 
              
                =
              
              
                yield
              
              
                'Nothing'
              
              
                print
              
              
                (
              
              
                '-- 協程接收到了數據: {!r} -- '
              
              
                .
              
              
                format
              
              
                (
              
              x
              
                )
              
              
                )
              
              
                >>
              
              
                >
              
               coro 
              
                =
              
               coroutine
              
                (
              
              
                )
              
              
                <
              
              generator 
              
                object
              
               coroutine at 
              
                0x10bbb2408
              
              
                >
              
              
                >>
              
              
                >
              
              
                next
              
              
                (
              
              coro
              
                )
              
              
                -
              
              
                -
              
               協程開始 
              
                -
              
              
                -
              
              
Nothing

              
                >>
              
              
                >
              
               coro
              
                .
              
              send
              
                (
              
              
                77
              
              
                )
              
              
                -
              
              
                -
              
               協程接收到了數據
              
                :
              
              
                77
              
              
                -
              
              
                -
              
              
Traceback 
              
                (
              
              most recent call last
              
                )
              
              
                :
              
              
                .
              
              
                .
              
              
                .
              
              
StopIteration

            
          

上面的例子表明:

  1. 在協程中, yield 通常出現在表達式的右邊。
  2. 調用方先使用一次 .next() 執行 yield ‘Nothing’ 讓協程產出字符串 “Nothing” 并 懸停至至 yield 表達式這一行
  3. 調用方使用 .send() 發送數據給協程。
  4. 發送的 數據代替 yield 表達式 ,并賦給變量 x。
  5. 協程結束時與生成器一致,都會拋出 StopIteration 異常。

需要特別注意的地方有:
首先、調用方只有在協程停在了 yield 表達式時,才能調用 .send() 發送數據 ,否則,協程會拋出 TypeError 異常,如例二:

            
              
                >>
              
              
                >
              
               coro 
              
                =
              
               coroutine
              
                (
              
              
                )
              
              
                >>
              
              
                >
              
               coro
              
                .
              
              send
              
                (
              
              
                77
              
              
                )
              
              
Traceback 
              
                (
              
              most recent call last
              
                )
              
              
                :
              
              
                .
              
              
                .
              
              
                .
              
              
                in
              
               coro
              
                .
              
              send
              
                (
              
              
                77
              
              
                )
              
              
TypeError
              
                :
              
               can't send non
              
                -
              
              
                None
              
               value to a just
              
                -
              
              started generator

            
          

懸停在 yield 表達式的協程狀態是 GEN_SUSPENDED ,你可以使用 inspect.getgeneratorstate(...) 函數確定協程的狀態。

其次、調用方使用 .send(y) 發送的數據會代替協程中的 yield 表達式 ,在上例中,發送的數據 y 是 77 ,77 代替了 yield 表達式,并賦給了變量 x。

最后、當賦值完畢后、協程會繼續前進至下一個 yield 關鍵字并懸停 ,直至結束從而拋出 StopIteration 異常。

你可以把 .send( y ) 看做兩個部分的結合,即:

  1. yield 表達式 = y
  2. .next()

這樣一來,擁有 .send()方法的生成器,完全符合了協程的定義,它可以通 過 .send() 接受調用方傳遞的值,并且可以通過 yield 產出值給調用方。

不過,此時我們沒有辦法在一創建協程時,立馬使用它。

你必須要先使用一次 .next() 讓協程懸停在 yield 表達式那一行,從而使協程轉變至 GEN_SUSPENDED 狀態 。這樣的行為被稱作 預激協程。

預激協程

毫無疑問,預激協程是一個很容易被遺忘的步驟。
需要使用 .send() 發送數據之前還必須使用一次 .next(),這讓人感到厭煩。

我們有什么辦法能夠自動預激協程呢?

有一種方法是使用能夠提前調用一次 .next() 的裝飾器,如下面這個 coroutine 裝飾器:

            
              
                # BEGIN CORO_DECO
              
              
                >>
              
              
                >
              
              
                from
              
               functools 
              
                import
              
               wraps


              
                >>
              
              
                >
              
              
                def
              
               coroutine_deco
              
                (
              
              func
              
                )
              
              
                :
              
              
                """Decorator: primes `func` by advancing to first `yield`"""
              
              
        @wraps
              
                (
              
              func
              
                )
              
              
                #使用 functools.wraps 裝飾器獲得源 func 的所有參數 "*args,**kwargs"
              
              
                def
              
              
                primer
              
              
                (
              
              
                *
              
              args
              
                ,
              
              
                **
              
              kwargs
              
                )
              
              
                :
              
               
            gen 
              
                =
              
               func
              
                (
              
              
                *
              
              args
              
                ,
              
              
                **
              
              kwargs
              
                )
              
              
                #使用源生成器函數獲取生成器
              
              
                next
              
              
                (
              
              gen
              
                )
              
              
                #調用 .next 方法
              
              
                return
              
               gen 
              
                #返回調用 .next 方法后的生成器
              
              
                return
              
               primer
    
              
                # END CORO_DECO
              
            
          

網上有多個類似的裝飾器。這個改自 ActiveState 中的一個訣竅——Pipeline made of coroutines,作者是 Chaobin Tang,而他是受到了 David Beazley 的啟發。—— 《流暢的 python 》

使用這個裝飾器后,現在我們再運行例二的代碼就不會報 TypeError 異常,而是會正常運行了,如下:

            
              @coroutine_deco

              
                >>
              
              
                >
              
              
                def
              
              
                coroutine
              
              
                (
              
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              
                '-- 協程開始 --'
              
              
                )
              
              
        x 
              
                =
              
              
                yield
              
              
                'Nothing'
              
              
                print
              
              
                (
              
              
                '協程接收到了數據: {!r}'
              
              
                .
              
              
                format
              
              
                (
              
              x
              
                )
              
              
                )
              
              
                >>
              
              
                >
              
               coro 
              
                =
              
               coroutine
              
                (
              
              
                )
              
              
                -
              
              
                -
              
               協程開始 
              
                -
              
              
                -
              
              
                >>
              
              
                >
              
              
                import
              
               inspect

              
                >>
              
              
                >
              
               inspect
              
                .
              
              getgeneratorstate
              
                (
              
              coro
              
                )
              
              
GEN_SUSPENDED

              
                >>
              
              
                >
              
               cro
              
                .
              
              send
              
                (
              
              
                77
              
              
                )
              
              
協程接收到了數據
              
                :
              
              
                77
              
              
Traceback 
              
                (
              
              most recent call last
              
                )
              
              
                :
              
              
                .
              
              
                .
              
              
                .
              
              
StopIteration

              
                >>
              
              
                >
              
              inspect
              
                .
              
              getgeneratorstate
              
                (
              
              coro
              
                )
              
              
GEN_CLOSED

            
          

該例子有如下行為需要注意:

  • 在創建協程 coro 對象后,直接輸出了 “-- 協程開始 --” 字符串,這表明, 在創建協程對象后,其自動調用了一次 next() 方法。
  • 使用 inspect.getgeneratorstate 查看協程的狀態,發現其已經是 GEN_SUSPENDED 狀態, 說明協程內部已經懸停在 yield 關鍵字處。
  • 能夠直接調用 .send() 方法而不用事先使用 .next() 了。
  • 協程結束時的狀態是 GEN_CLOSED

協程還有一個很常用的方法 —— .close() 用于提前關閉協程。使用該方法后,協程會在 yield 表達式那一行拋出 GeneratorExit 異常。

有時,我們需要協程在結束了所有工作時,返回一個值, 這在 python 3.3 之前是不可能的,因為在協程的方法體中寫 return 關鍵字會報句法錯誤。

讓協程在終止時返回值

我們可以在 python 3.3 及之后的版本中 讓終止的協程返回想要的值 ,只是獲取返回值的方法比較曲折。

下面的例三,定義了一個動態計算平均值的協程,并讓其在結束工作(接受到 None 值)后 返回一個元組 ,該元組保存著目前為止收到的數據個數以及最終的平均值。

            
              
                >>
              
              
                >
              
              
                from
              
               collections 
              
                import
              
               namedtuple


              
                >>
              
              
                >
              
               Result 
              
                =
              
               namedtuple
              
                (
              
              
                'Result'
              
              
                ,
              
              
                'count average'
              
              
                )
              
              
                >>
              
              
                >
              
              
                def
              
              
                averager
              
              
                (
              
              
                )
              
              
                :
              
              
        total 
              
                =
              
              
                0.0
              
              
        count 
              
                =
              
              
                0
              
              
        average 
              
                =
              
              
                None
              
              
                while
              
              
                True
              
              
                :
              
              
            term 
              
                =
              
              
                yield
              
               average
            
              
                if
              
               term 
              
                is
              
              
                None
              
              
                :
              
              
                break
              
                
            total 
              
                +=
              
               term
            count 
              
                +=
              
              
                1
              
              
            average 
              
                =
              
               total
              
                /
              
              count
        
              
                return
              
               Result
              
                (
              
              count
              
                ,
              
               average
              
                )
              
            
          

該函數有以下行為:

            
              
                >>
              
              
                >
              
               coro_avg 
              
                =
              
               averager
              
                (
              
              
                )
              
              
                >>
              
              
                >
              
              
                next
              
              
                (
              
              coro_avg
              
                )
              
              
                # <1>
              
              
                >>
              
              
                >
              
               coro_avg
              
                .
              
              send
              
                (
              
              
                10
              
              
                )
              
              
                # <2>
              
              
                10.0
              
              
                >>
              
              
                >
              
               coro_avg
              
                .
              
              send
              
                (
              
              
                30
              
              
                )
              
              
                20.0
              
              
                >>
              
              
                >
              
               coro_avg
              
                .
              
              send
              
                (
              
              
                6.5
              
              
                )
              
              
                15.5
              
              
                >>
              
              
                >
              
               coro_avg
              
                .
              
              send
              
                (
              
              
                None
              
              
                )
              
              
                # <3>
              
              
Traceback 
              
                (
              
              most recent call last
              
                )
              
              
                :
              
              
                .
              
              
                .
              
              
                .
              
              
StopIteration
              
                :
              
               Result
              
                (
              
              count
              
                =
              
              
                3
              
              
                ,
              
               average
              
                =
              
              
                15.5
              
              
                )
              
            
          

注釋:
① : 手動預激協程。
② : 調用 .send(10) 返回目前傳入所有數的平均值10、之后每傳入一個數都能實時計算所有數的平均值。
③ : 傳入 None ,手動結束該協程。

注意到,和往常一樣,結束后 協程拋出了 StopIteration 異常 。不一樣的是, 該異常保存著返回的值 ,即 Result 對象。

return 表達式的值會偷偷傳給調用方,賦值給 StopIteration 異常的一個屬性。這樣做有點不合常理,但是能 保留生成器對象的常規行為 ——耗盡時拋出 StopIteration 異常。

改造上面的代碼,手動捕獲異常,獲取返回值,可以這樣寫:

            
              
                >>
              
              
                >
              
               coro_avg 
              
                =
              
               averager
              
                (
              
              
                )
              
              
                >>
              
              
                >
              
              
                next
              
              
                (
              
              coro_avg
              
                )
              
              
                >>
              
              
                >
              
               coro_avg
              
                .
              
              send
              
                (
              
              
                10
              
              
                )
              
              
                10.0
              
              
                >>
              
              
                >
              
               coro_avg
              
                .
              
              send
              
                (
              
              
                30
              
              
                )
              
              
                20.0
              
              
                >>
              
              
                >
              
               coro_avg
              
                .
              
              send
              
                (
              
              
                6.5
              
              
                )
              
              
                15.5
              
              
                >>
              
              
                >
              
              
                try
              
              
                :
              
              
        coro_avg
              
                .
              
              send
              
                (
              
              
                None
              
              
                )
              
              
                except
              
               StopIteration 
              
                as
              
               exc
              
                :
              
               
        result 
              
                =
              
               exc
              
                .
              
              value

              
                >>
              
              
                >
              
               result 
Result
              
                (
              
              count
              
                =
              
              
                3
              
              
                ,
              
               average
              
                =
              
              
                15.5
              
              
                )
              
            
          

目前,我們說明了如何讓 生成器接收調用方提供的值從而進化成協程 、如何 使用裝飾器自動預激協程 、以及 如何從協程獲取看起來很有用的返回值。

使用協程似乎太麻煩了點 !

不是嗎? 為了避免麻煩,我們必須自己定義一個自動預激協程的裝飾器,為了獲取協程的返回值,我們還必須捕捉異常,并獲取異常的 value 屬性。

有什么辦法能夠消除這些麻煩呢?(不用自定義預激裝飾器也不用捕獲異常以獲得返回值)

在 python 3.3 以后,有一個新的句法能夠幫助我們解決這些麻煩,即 yield from

yield from 及其工作原理

使用 yield from 關鍵字 不僅能自動預激協程 自動提取異常的 value 屬性返回值作為 yield from 表達式的值 ,還能夠 作為調用方和協程之間的通道

如果將例三中的 averager() 改編成使用 yield from 關鍵字來實現,會是例四的代碼:

            
              
                >>
              
              
                >
              
              
                from
              
               collections 
              
                import
              
               namedtuple


              
                >>
              
              
                >
              
               Result 
              
                =
              
               namedtuple
              
                (
              
              
                'Result'
              
              
                ,
              
              
                'count average'
              
              
                )
              
              
                >>
              
              
                >
              
              
                def
              
              
                averager
              
              
                (
              
              
                )
              
              
                :
              
              
        total 
              
                =
              
              
                0.0
              
              
        count 
              
                =
              
              
                0
              
              
        average 
              
                =
              
              
                None
              
              
                while
              
              
                True
              
              
                :
              
              
            term 
              
                =
              
              
                yield
              
               average
            
              
                if
              
               term 
              
                is
              
              
                None
              
              
                :
              
              
                break
              
                
            total 
              
                +=
              
               term
            count 
              
                +=
              
              
                1
              
              
            average 
              
                =
              
               total
              
                /
              
              count
        
              
                return
              
               Result
              
                (
              
              count
              
                ,
              
               average
              
                )
              
              
                >>
              
              
                >
              
               result 
              
                =
              
              
                set
              
              
                (
              
              
                )
              
              
                # <1>
              
              
                >>
              
              
                >
              
              
                def
              
              
                yf_averager
              
              
                (
              
              result
              
                )
              
              
                :
              
              
                # <2>
              
              
                while
              
              
                True
              
              
                :
              
              
                # <3>
              
              
            r 
              
                =
              
              
                yield
              
              
                from
              
               averager
              
                (
              
              
                )
              
              
                # <4>
              
              
            result
              
                .
              
              add
              
                (
              
              r
              
                )
              
              
                >>
              
              
                >
              
               yfa 
              
                =
              
               yf_averager
              
                (
              
              result
              
                )
              
              
                # <5>
              
              
                >>
              
              
                >
              
              
                next
              
              
                (
              
              yfa
              
                )
              
              
                # <6>
              
              
                >>
              
              
                >
              
               yfa
              
                .
              
              send
              
                (
              
              
                10
              
              
                )
              
              
                # <7>
              
              
                10.0
              
              
                >>
              
              
                >
              
               yfa
              
                .
              
              send
              
                (
              
              
                30
              
              
                )
              
              
                20.0
              
              
                >>
              
              
                >
              
               yfa
              
                .
              
              send
              
                (
              
              
                6.5
              
              
                )
              
              
                15.5
              
              
                >>
              
              
                >
              
               yfa
              
                .
              
              send
              
                (
              
              
                None
              
              
                )
              
              
                # <8>
              
              
                >>
              
              
                >
              
               result  
              
                # <9>
              
              
                {
              
              Result
              
                (
              
              count
              
                =
              
              
                3
              
              
                ,
              
               average
              
                =
              
              
                15.5
              
              
                )
              
              
                }
              
            
          

在例四中,averager() 方法并沒有做任何改變
解釋:
①:創建 result 集合以在調用方收集結果。
②:yield from 關鍵字的 載體函數 ,有時也叫“委派生成器” ,設立這一函數是因為 在函數外部使用 yield from(以及 yield)會導致句法錯誤。
③:使用循環以保證傳入 None 時 yf_averager 生成器不拋出 StopIteration 異常 從而直接結束整個程序,若是如此,我們便觀察不到 result 了。
④:使用 yield from 關鍵字后面是 協程 、前面是接收協程最終返回值的變量 r,這個 r 我們最終會放在全局變量 result 集合中。還有一點需要注意、 當函數體重含有 yield from 那么它本身就是協程了
⑤:新建 yf_averager 協程,以 建立調用方與 averager 協程的通道
⑥:預激 yf_averager 協程
⑦:使用 .send()發送數據
⑧:發送 None 以結束 averager 協程
⑨:展示 result 集合中的值,確認接收到了最終的結果

上面如果上面這個例子你不怎么看得懂,沒關系,我會在后面解釋。
你現在 只需要知道 yield from 有這些行為:

  1. 在例四中,我們沒有預激 averager 協程,但是它能夠正常工作。 這說明 yield from 關鍵字會自動預激協程。
  2. 調用方使用委派生成器 yf_averager 傳入的值會送到 averager 里,并且調用方可以接收到 averager 協程處理后返回的值。 這說明了使用 yield from 的委派生成器 yf_averager 可以在調用方和協程之間建立通道,傳輸數據。
  3. 在獲取 averager 結果時,我們沒有捕獲異常,而是在第 22 行代碼中將返回值直接賦給了變量 r。 這說明了協程的最終返回值會成為 yield from 表達式的值。

yield from 關鍵字的原理

接下來這段偽碼等效于 RESULT = yield from EXPR 語句 。它能夠幫助你理解例四中 yield from 的行為

這并不是完整的偽代碼,它去除了 .throw()和 .close()方法,只處理 StopIteration 異常。完整的偽碼在這里 -> yield_from_expansion,不過在理解其功能的方面上,這足夠了。

            
              _i 
              
                =
              
              
                iter
              
              
                (
              
              EXPR
              
                )
              
              
                # <1>
              
              
                try
              
              
                :
              
              
    _y 
              
                =
              
              
                next
              
              
                (
              
              _i
              
                )
              
              
                # <2>
              
              
                except
              
               StopIteration 
              
                as
              
               _e
              
                :
              
              
    _r 
              
                =
              
               _e
              
                .
              
              value  
              
                # <3>
              
              
                else
              
              
                :
              
              
                while
              
              
                1
              
              
                :
              
              
                # <4>
              
              
        _s 
              
                =
              
              
                yield
              
               _y  
              
                # <5>
              
              
                try
              
              
                :
              
              
            _y 
              
                =
              
               _i
              
                .
              
              send
              
                (
              
              _s
              
                )
              
              
                # <6>
              
              
                except
              
               StopIteration 
              
                as
              
               _e
              
                :
              
              
                # <7>
              
              
            _r 
              
                =
              
               _e
              
                .
              
              value
            
              
                break
              
              

RESULT 
              
                =
              
               _r  
              
                # <8>
              
            
          

解釋:
① :EXPR 可以是任何可迭代的對象,因為獲取迭代器 _i(這是子生成器,例子中的 averager 協程)使用的是 iter() 函數。
② : 預激子生成器(averager 協程);結果保存在 _y 中,作為產出的第一個值。
③ :如果拋出 StopIteration 異常, 獲取異常對象的 value 屬性,賦值給 _r ——這是最簡單情況下的返回值(RESULT)。
④ :運行這個循環時,委派生成器(yf_averager 生成器)會阻塞, 只作為調用方和子生成器之間的通道
⑤ :**產出子生成器當前產出的元素;等待調用方發送 _s 中保存的值。**因為這一個 yield 表達式和 ⑥ 中的send(), 委派生成器也變成了協程。
⑥ :嘗試讓子生成器向前執行, 轉發調用方發送的 _s
⑦ :如果子生成器拋出 StopIteration 異常, 獲取 value 屬性的值,賦值給 _r ,然后退出循環,讓委派生成器恢復運行。
⑧ : 返回的結果(RESULT)是 _r ,即整個 yield from 表達式的值。

以上的偽代碼和注釋,幾戶原封不動的搬了《流程的 python 》里的解釋,我只是增加了一些注釋。因為我想不出如何更好的總結 yield from 關鍵字的原理。

注意,因為 yf_averager 是帶 yield 關鍵字的生成器,所以在 ⑧ 結束后, 若找不到下一個 yield 關鍵字,那么 yf_averager 生成器會拋出 StopIteration 異常 ,這是我在例四中設立 while 循環 ③ 的直接原因。

我建議你在看懂這段偽代碼的基礎上再去 回顧例四 ,這下你 應該豁然開朗 了。如果還看不懂的話,我建議你多花些時間去看《流程的 python 》的第十六章,該章用了60多頁的篇幅把 python 協程講得很通透。

結語

本篇博文中,我用了四個小節敘述了我理解中的協程、及其使用技巧。在一開始,我講述了 協程是什么 ,及 如何在 python 2.2 及以后的版本中用生成器構建協程 ;然后我講述了 協程的必要操作(預激)的自動化方法 如何在 python 3.3 及以后的版本中獲取協程的返回值 ;最后,我講述了方便的 yield from 關鍵字的用法、行為 以及 它的主要原理

如果你想要知道 協程的具體用處 ,《流程的 python 》的第十六章中舉了一個離散事件仿真的例子—— 出租車隊運營仿真 。該仿真程序會創建幾輛出租車,并模擬他們并行運作(離開倉庫、尋找乘客、乘客下次、四處徘徊、回家)。對于說明如何使用協程做離散事件仿真是一個很好的例子。

這是那個出租車隊運營仿真例子的源碼 -> taxi_sim

我希望你看完這篇博文后能夠有所收獲、如果你看到了一些錯誤,請在評論中指出。


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 曰批免费视频播放在线看片一 | 久久国产网站 | 天天曰天天操 | 奇米影视奇奇米色狠狠色777 | 九九九网站| 四虎影视库国产精品一区 | 精品视频香蕉尹人在线 | 久热这里只有精品6 | 午夜在线不卡 | 久久久综合久久 | 精品综合久久久久久蜜月 | 久久精品视频7 | 亚洲精彩 | 欧美人与动性xxxxbbbb | 99久久久久国产精品免费 | 午夜性色吃奶添下面69影院 | 久草最新网址 | 日本伦理中文字幕 | 日韩一级特黄毛片在线看 | 香蕉国产人午夜视频在线观看 | 国产精品中文字幕在线 | 国产情侣久久精品 | 久久久精品一区二区三区 | 久久这里只有精品久久 | 再猛点深使劲爽日本免费视频 | 天天综合网天天做天天受 | 亚洲五月婷婷 | 久久91亚洲精品久久91综合 | 成人深夜视频在线观看 | 一区二区三区四区产品乱码伦 | 亚洲成a人片毛片在线 | 美女很黄很黄免费 | 日韩爱爱 | 亚洲欧美一区二区三区麻豆 | 波多野结中文字幕在线69视频 | 日日操操 | 酒色网站 | 国产精品一区久久 | 天天操天天艹 | 看全色黄大色大片免费视频 | 欧美一区二区三区在线视频 |