日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

python generator與coroutine

系統(tǒng) 1783 0

python ?generator與coroutine

?

協(xié)程

簡單介紹

協(xié)程,又稱微線程,纖程,英文名Coroutine。
協(xié)程是一種用戶態(tài)的輕量級線程,又稱微線程。
協(xié)程擁有自己的寄存器上下文和棧,調(diào)度切換時(shí),將寄存器上下文和棧保存到其他地方,在切回來的時(shí)候,恢復(fù)先前保存的寄存器上下文和棧。因此:協(xié)程能保留上一次調(diào)用時(shí)的狀態(tài)(即所有局部狀態(tài)的一個(gè)特定組合),每次過程重入時(shí)就相當(dāng)于進(jìn)入上一次調(diào)用的狀態(tài),換種說法:進(jìn)入上一次離開時(shí)所處邏輯流的位置。

?

優(yōu)缺點(diǎn)

優(yōu)點(diǎn):
1.無需線程上下文切換的開銷
2.無需原子操作鎖定及同步的開銷
3.方便切換控制流,簡化編程模型
4.高并發(fā)+高擴(kuò)展性+低成本:一個(gè)CPU支持上萬的協(xié)程都不是問題。所以很適合用于高并發(fā)處理。
所謂原子操作是指不會被線程調(diào)度機(jī)制打斷的操作;這種操作一旦開始,就一直運(yùn)行到結(jié)束,中間不會有任何 context switch (切換到另一個(gè)線程)。
原子操作可以是一個(gè)步驟,也可以是多個(gè)操作步驟,但是其順序是不可以被打亂,或者切割掉只執(zhí)行部分。視作整體是原子性的核心。

缺點(diǎn):
1.無法利用多核資源:協(xié)程的本質(zhì)是個(gè)單線程,它不能同時(shí)將 單個(gè)CPU 的多個(gè)核用上,協(xié)程需要和進(jìn)程配合才能運(yùn)行在多CPU上.當(dāng)然我們?nèi)粘K帉懙慕^大部分應(yīng)用都沒有這個(gè)必要,除非是cpu密集型應(yīng)用。
但是多進(jìn)程+協(xié)程,可以充分利用多核,又充分發(fā)揮協(xié)程的高效率,可獲得極高的性能。
2.進(jìn)行阻塞(Blocking)操作(如IO時(shí))會阻塞掉整個(gè)程序。

?

協(xié)程可以用在哪些場景呢

            
              可以歸納為非阻塞等待的場景,如游戲編程,異步IO,事件驅(qū)動。
            
          

?

協(xié)程詳解

Python對協(xié)程的支持是通過generator(生成器)實(shí)現(xiàn)的。

要理解生成器,我們先要理解迭代器。什么是迭代器?

            在python中一個(gè)可以迭代的數(shù)據(jù)調(diào)用iter方法,就可以得到一個(gè)迭代器,這個(gè)迭代器一定具有next方法,在調(diào)用這個(gè)迭代器的next方法時(shí),迭代器就回返回它的下一個(gè)值,當(dāng)?shù)髦袥]有值可以返回了,就回拋出一個(gè)名為StopIteration的異常,停止迭代。
          

什么是生成器?

?生成器是一個(gè)特殊的程序,可以被用作控制循環(huán)的迭代行為,python中生成器是迭代器的一種,使用yield返回值函數(shù),每次調(diào)用yield會暫停,而可以使用next()函數(shù)和send()函數(shù)恢復(fù)生成器。
?生成器是個(gè)比較特殊的可迭代對象,它與其他的可迭代對象不太一樣的地方,其他的可迭代對象需要調(diào)用iter方法,返回個(gè)迭代器對象,然后通過迭代器對象去執(zhí)行next方法,獲取迭代器中的值,但是生成器直接可以被迭代,無需執(zhí)行iter方法。

至少我們現(xiàn)在要明白

1.帶有 yield 的函數(shù)不再是一個(gè)普通函數(shù),而是一個(gè)生成器generator.
2.生成器是可以迭代的,使用next()方法.
3.生成器(generator)能夠迭代的關(guān)鍵是它有一個(gè)next()方法,工作原理就是通過重復(fù)調(diào)用next()方法,直到捕獲一個(gè)異常。

4.協(xié)程是通過生成器的實(shí)現(xiàn)的
5.協(xié)程有四個(gè)狀態(tài),如下:
?'GEN_CREATED' 等待開始執(zhí)行。
?'GEN_RUNNING' 解釋器正在執(zhí)行。
?'GEN_SUSPENDED' 在 yield 表達(dá)式處暫停。
?'GEN_CLOSED' 執(zhí)行結(jié)束。

?

第一個(gè)示例程序

test為生成器,即可以迭代,我們可以使用next方法迭代。

第11行創(chuàng)建生成器test,在python的函數(shù)(function)定義中,只要出現(xiàn)了yield表達(dá)式(Yield expression),那么事實(shí)上定義的是一個(gè) generator function , 調(diào)用這個(gè)generator function返回值是一個(gè) generator。

第12行打印生成器。

第14行我們可以了生成器的狀態(tài),結(jié)果為:GEN_CREATED。

第15行第一次執(zhí)行next方法,send和next操作都是調(diào)用生成器,而第一調(diào)用生成器就是啟動生成器,啟動生成器必須使用next()語句或是send(None)啟動生成器,不能使用send發(fā)送一個(gè)非None的值,例如send(None),程序運(yùn)行到y(tǒng)ield 1,程序在這里暫停執(zhí)行,并返回1,我們要明白在這里yield有了return的功能,返回了1,而且還暫停了程序。

第16行我們再次打印生成器的狀態(tài),結(jié)果:GEN_SUSPENDED。

第17行第二次執(zhí)行next方法,程序運(yùn)行到y(tǒng)ield 2,程序在這里暫停,并返回2。

現(xiàn)在就很清晰了,使用yield可以切出生成器,它還有return的功能,切進(jìn)生成器可以使用next()方法。

調(diào)用生成器的next(),將運(yùn)行到y(tǒng)ield位置,此時(shí)暫停執(zhí)行環(huán)境,并返回這條語句yield關(guān)鍵詞后面跟隨的值。?這是next()的使用方法。

            
               1
            
            
              import
            
            
               inspect

            
            
               2
            
            
              def
            
            
               func1():

            
            
               3
            
            
              yield
            
             1

            
               4
            
            
              print
            
            (
            
              "
            
            
              第一個(gè)yield執(zhí)行完成~
            
            
              "
            
            
              )

            
            
               5
            
            
              yield
            
             2

            
               6
            
            
              print
            
            (
            
              "
            
            
              第二個(gè)yield執(zhí)行完成~
            
            
              "
            
            
              )

            
            
               7
            
            
              yield
            
             3

            
               8
            
            
              print
            
            (
            
              "
            
            
              第三個(gè)yield執(zhí)行完成~
            
            
              "
            
            
              )

            
            
               9
            
            
              10
            
            
              11
            
             test =
            
               func1()

            
            
              12
            
            
              print
            
            
              (test)

            
            
              13
            
            
              14
            
            
              print
            
            (
            
              "
            
            
              還未執(zhí)行next:
            
            
              "
            
            
              ,inspect.getgeneratorstate(test))

            
            
              15
            
            
              next(test)

            
            
              16
            
            
              print
            
            (
            
              "
            
            
              第一次執(zhí)行next:
            
            
              "
            
            
              ,inspect.getgeneratorstate(test))

            
            
              17
            
            
              next(test)

            
            
              18
            
            
              print
            
            (
            
              "
            
            
              第二次執(zhí)行next:
            
            
              "
            
            
              ,inspect.getgeneratorstate(test))

            
            
              19
            
            
              next(test)

            
            
              20
            
            
              print
            
            (
            
              "
            
            
              第三次執(zhí)行next:
            
            
              "
            
            
              ,inspect.getgeneratorstate(test))

            
            
              21
            
            
              next(test)

            
            
              22
            
            
              print
            
            (
            
              "
            
            
              第四次執(zhí)行next:
            
            
              "
            
            ,inspect.getgeneratorstate(test))
          

?

運(yùn)行結(jié)果:

            
              
                
Traceback (most recent call last):
還未執(zhí)行next: GEN_CREATED
第一次執(zhí)行next: GEN_SUSPENDED
第一個(gè)yield執(zhí)行完成
              
              ~
              
                
第二次執(zhí)行next: GEN_SUSPENDED
第二個(gè)yield執(zhí)行完成
              
              ~
              
                
  File 
              
              
                "
              
              
                C:/Pycham/異步編程/test3.py
              
              
                "
              
              , line 21, 
              
                in
              
              
                
                  
第三次執(zhí)行next: GEN_SUSPENDED
第三個(gè)yield執(zhí)行完成
                
                ~
                
                  
    next(test)
StopIteration
                
              
            
          

?

?

第二個(gè)示例程序

在上面的列子我們使用next()切進(jìn)了生成器,但是每次切換進(jìn)生成器,都沒有傳入?yún)?shù),接下來將介紹send()方法,send()方法不僅可以切進(jìn)生成器,而且還可以攜帶參數(shù)。

除了next和send方法,generator還提供了兩個(gè)實(shí)用的方法,throw和close,這兩個(gè)方法加強(qiáng)了caller對generator的控制。send方法可以傳遞一個(gè)值給generator,throw方法在generator掛起的地方拋出異常,close方法讓generator正常結(jié)束(之后就不能再調(diào)用next send了)。

            
               1
            
            
              import
            
            
               sys

            
            
               2
            
            
              def
            
            
               func2(a):

            
            
               3
            
            
              print
            
            (
            
              '
            
            
              -> Started: a =
            
            
              '
            
            
              , a)

            
            
               4
            
                 b = 
            
              yield
            
            
               a

            
            
               5
            
            
              print
            
            (
            
              '
            
            
              -> Received: b =
            
            
              '
            
            
              , b)

            
            
               6
            
                 c = 
            
              yield
            
             a +
            
               b

            
            
               7
            
            
              print
            
            (
            
              '
            
            
              -> Received: c =
            
            
              '
            
            
              , c)

            
            
               8
            
            
               9
            
             test = func2(2
            
              )

            
            
              10
            
             value = next(test)
            
              #
            
            
               協(xié)程執(zhí)行到`b = yield a`處暫停,等待為b賦值,并返回a
            
            
              11
            
            
              print
            
            
              (value)

            
            
              12
            
             value = test.send(88)
            
              #
            
            
               協(xié)程執(zhí)行到`c = yield a + b`處暫停,等待為c賦值,并返回a + b
            
            
              13
            
            
              print
            
            
              (value)

            
            
              14
            
            
              try
            
            
              :

            
            
              15
            
                 test.send(11
            
              )

            
            
              16
            
            
              except
            
            
               StopIteration:

            
            
              17
            
                 sys.exit(0)
          

運(yùn)行結(jié)果:

            -> Started: a = 2
2
-> Received: b = 88
90
-> Received: c = 11
          

?

?

第三個(gè)示例程序

傳統(tǒng)的生產(chǎn)者-消費(fèi)者模型是一個(gè)線程寫消息,一個(gè)線程取消息,通過鎖機(jī)制控制隊(duì)列和等待,但一不小心就可能死鎖。如果改用協(xié)程,生產(chǎn)者生產(chǎn)消息后,直接通過yield跳轉(zhuǎn)到消費(fèi)者開始執(zhí)行,待消費(fèi)者執(zhí)行完畢后,切換回生產(chǎn)者繼續(xù)生產(chǎn),效率極高:

            
               1
            
            
              import
            
            
               time

            
            
               2
            
            
               3
            
            
              def
            
            
               cumtom(name):

            
            
               4
            
            
              print
            
            (
            
              '
            
            
              %s準(zhǔn)備吃包子
            
            
              '
            
             %
            
              name)

            
            
               5
            
                 time.sleep(1
            
              )

            
            
               6
            
            
              while
            
             1
            
              :

            
            
               7
            
                     count=
            
              yield
            
            
               8
            
            
              print
            
            (
            
              '
            
            
              %s吃到第%d個(gè)包子
            
            
              '
            
             %
            
              (name,count))

            
            
               9
            
            
              10
            
            
              def
            
            
               producter():

            
            
              11
            
            
                  next(con1)

            
            
              12
            
            
                  next(con2)

            
            
              13
            
            
              #
            
            
               con1.__next__()
            
            
              14
            
            
              #
            
            
               con2.__next__()
            
            
              15
            
                 n=1

            
              16
            
            
              while
            
             1
            
              :

            
            
              17
            
                     time.sleep(1
            
              )

            
            
              18
            
            
              print
            
            (
            
              '
            
            
              已經(jīng)生產(chǎn)出來%d、%d個(gè)包子
            
            
              '
            
             %(n,n+1
            
              ))

            
            
              19
            
            
              #
            
            
              通過send方法通知
            
            
              20
            
            
                      con1.send(n)

            
            
              21
            
                     con2.send(n+1
            
              )

            
            
              22
            
                     n+=2

            
              23
            
            
              24
            
            
              #
            
            
              cumtom函數(shù)里面有yield,這里傳遞參數(shù),會創(chuàng)建一個(gè)生成器對象,(提前做了預(yù)處理)
            
            
              25
            
             con1=cumtom(
            
              '
            
            
              cumtom1
            
            
              '
            
            
              )

            
            
              26
            
             con2=cumtom(
            
              '
            
            
              cumtom2
            
            
              '
            
            
              )

            
            
              27
            
             producter()
          

?


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

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

【本文對您有幫助就好】

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

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 郴州市| 息烽县| 岳西县| 集贤县| 衡水市| 长兴县| 乐清市| 务川| 沙湾县| 台湾省| 汝州市| 射洪县| 扶沟县| 饶河县| 南部县| 东海县| 宜良县| 溧水县| 乡城县| 高邑县| 临潭县| 郎溪县| 宜良县| 洪泽县| 西充县| 梨树县| 万盛区| 正镶白旗| 翁源县| 斗六市| 右玉县| 奉化市| 凤城市| 云和县| 丰台区| 屏边| 潼关县| 西贡区| 博乐市| 宜良县| 宝山区|