Python 進階 之 協程

協程的概念級描述(與線程對比):轉自知乎 連接python

  線程有兩個必需要處理的問題:一是碰着阻塞式I\O會致使整個進程被掛起;異步

                二是因爲缺少時鐘阻塞,進程須要本身擁有調度線程的能力。async

  若是一種實現使得每一個線程須要本身經過調用某個方法,主動交出控制權。那麼咱們就稱這種線程是協做式的,便是協程。函數

在Python中關於協程的實現方式有三種:oop

  1. 最初的生成器變形yield/send
  2. 引入@asyncio.coroutine和yield from
  3. 在Python3.5版本中引入async/await關鍵字

如下代碼均在Centos 7 Python3.6調試經過!網站

簡單的yield使用描述:
spa

def fun():
    index = 0
    while True:
        yield index
        index += 1
        if index > 3 :
            break
for i in fun():
    print (i)
輸出:0 1 2 3

在此例中yield作的事是:線程

  1:將函數fun的返回值設定爲一個生成器調試

  2:每次運行至yield index 時會將index的值做爲生成器的下一個元素返回值for循環而且被賦值給變量i,用print輸出出來code

簡單的yield/send使用描述:

def fun():
    index = 0
    while True:
        value = yield index
        print ("value=" + str(value))
        print ("index=" + str(index))
        index += 1
        if index > 3 :
            break
funobj = fun()
print (type(funobj))
print ("next=" + str(next(funobj)))
for i in funobj:
    print ("i=" + str(i))
    try:
        funobj.send(i+100)
    except StopIteration:
        print("it's stop")
輸出:

<class 'generator'>
next=0
value=None
index=0
i=1
value=101
index=1
value=None
index=2
i=3
value=103
index=3
it's stop

不是很精通,所以代碼有點亂。

解釋:

  首先聲明瞭fun函數,並將fun賦給了對面funobj,funobj是一個迭代器。next(funobj)初始化並啓動迭代器,程序開始運行fun函數至value = yield index(第一次)結束,yield返回了第一個index值0 next=0

  for i in funobj:啓動迭代器,所以此時send還未傳值,所以value和next都是空,value=None index=0 程序運行fun函數至value = yield index(第二次)結束,yield返回了第二個index值1 i=1

  注意以後send發送了值101,for再次啓動迭代器,從yield啓動時捕獲到此值101,value=101 index=101。此後相似。

  迭代器結束時會捕獲到 StopIteration異常,將此捕獲並輸出出來 it's stop

簡單的yield/send使用描述:

  yeild from語法就是將生成器函數中包括yield語句的部分邏輯封裝到一個子生成器函數中。而後在子生成器函數外面能夠作一些其餘的業務邏輯。整個生成器函數(包括子生成器函數)對外就是一個生成器函數。

def fun():
    index = 0
    while True:
        value = yield index
        print ("value=" + str(value))
        print ("index=" + str(index))
        index += 1
        if index > 3 :
            break

def fun2():
    print ("before ")
    yield from fun()
    print ("end ")

funobj = fun2()
print (type(funobj))
print ("next=" + str(next(funobj)))
for i in funobj:
    print ("i=" + str(i))
    try:
        funobj.send(i+100)
    except StopIteration:
        print("it's stop")

輸出:

<class 'generator'>
before 
next=0
value=None
index=0
i=1
value=101
index=1
value=None
index=2
i=3
value=103
index=3
end 
it's stop

 簡單的asyncio.coroutine使用描述:(參考自廖雪峯的官方網站

@asyncio.coroutine經過裝飾器調用,做用是把一個generator標記爲coroutine類型:

import asyncio

@asyncio.coroutine
def hello():
    print("Hello world!")
    # 異步調用asyncio.sleep(1):
    r = yield from asyncio.sleep(1)
    print("Hello again!")

# 獲取EventLoop:
loop = asyncio.get_event_loop()
# 執行coroutine
loop.run_until_complete(hello())
loop.close()

輸出:

Hello world!
Hello again!

簡單的asyncawait使用描述:

  asyncawait是針對coroutine的新語法,要使用新的語法,只須要作兩步簡單的替換:

  1. @asyncio.coroutine替換爲async
  2. yield from替換爲await

  示例代碼:

import asyncio

async def hello():
    print("Hello world!")
    r = await asyncio.sleep(1)
    print("Hello again!")

# 獲取EventLoop:
loop = asyncio.get_event_loop()
# 執行coroutine
loop.run_until_complete(hello())
loop.close()

 

  須要注意的是asyncawait只能用在Python 3.5以及後續版本,若是使用3.4版本,則仍需使用asyncio.coroutine和yield from方案。

  示例可能出現的報錯以下:

[root@jans test]# python3.6 c.py 
Hello world!
Hello again!
[root@jans test]# python3.4 c.py 
  File "c.py", line 3
    async def hello():
            ^
SyntaxError: invalid syntax
相關文章
相關標籤/搜索