python协成_Python协程(上)
幾個(gè)概念:
event_loop 事件循環(huán):程序開啟一個(gè)無限的循環(huán),程序員會(huì)把一些函數(shù)注冊到事件循環(huán)上。當(dāng)滿足事件發(fā)生的時(shí)候,調(diào)用相應(yīng)的協(xié)程函數(shù)。
coroutine 協(xié)程:協(xié)程對象,指一個(gè)使用async關(guān)鍵字定義的函數(shù),它的調(diào)用不會(huì)立即執(zhí)行函數(shù),而是會(huì)返回一個(gè)協(xié)程對象。協(xié)程對象需要注冊到事件循環(huán),由事件循環(huán)調(diào)用。
task 任務(wù):一個(gè)協(xié)程對象就是一個(gè)原生可以掛起的函數(shù),任務(wù)則是對協(xié)程進(jìn)一步封裝,其中包含任務(wù)的各種狀態(tài)。
future: 代表將來執(zhí)行或沒有執(zhí)行的任務(wù)的結(jié)果。它和task上沒有本質(zhì)的區(qū)別
async/await 關(guān)鍵字:python3.5 用于定義協(xié)程的關(guān)鍵字,async定義一個(gè)協(xié)程,await用于掛起阻塞的異步調(diào)用接口。
定義協(xié)程
通過async關(guān)鍵字定義一個(gè)協(xié)程(coroutine),協(xié)程也是一種對象。協(xié)程不能直接運(yùn)行,需要把協(xié)程加入到事件循環(huán)(loop),由后者在適當(dāng)?shù)臅r(shí)候調(diào)用協(xié)程。asyncio.get_event_loop方法可以創(chuàng)建一個(gè)事件循環(huán),然后使用run_until_complete將協(xié)程注冊到事件循環(huán),并啟動(dòng)事件循環(huán)。
import time
import asyncio
async def task(x):
print('Waiting: ', x)
await asyncio.sleep(x)
start = time.time()
coroutine = task(2)
loop = asyncio.get_event_loop()
loop.run_until_complete(coroutine)
print('用時(shí):', time.time()-start)
創(chuàng)建task
協(xié)程對象不能直接運(yùn)行,在注冊事件循環(huán)的時(shí)候,其實(shí)是run_until_complete方法將協(xié)程包裝成為了一個(gè)任務(wù)(task)對象。所謂task對象是Future類的子類。保存了協(xié)程運(yùn)行后的狀態(tài),用于未來獲取協(xié)程的結(jié)果。
import asyncio
import time
async def task(x):
print('Waiting: ', x)
await asyncio.sleep(x)
start = time.time()
coroutine = task(2)
loop = asyncio.get_event_loop()
task = loop.create_task(coroutine) # task = asyncio.ensure_future(coroutine)
print(task)
loop.run_until_complete(task)
print(task)
print('用時(shí):', time.time() - start)
創(chuàng)建task后,task在加入事件循環(huán)之前是pending狀態(tài),執(zhí)行之后是finished狀態(tài)。
asyncio.ensure_future(coroutine) 和loop.create_task(coroutine)
都可以創(chuàng)建一個(gè)task,run_until_complete的參數(shù)是一個(gè)futrue對象。當(dāng)傳入一個(gè)協(xié)程,其內(nèi)部會(huì)自動(dòng)封裝成task,task是Future的子類。isinstance(task, asyncio.Future)將會(huì)輸出True。
綁定回調(diào)
綁定回調(diào),在task執(zhí)行完畢的時(shí)候可以獲取執(zhí)行的結(jié)果,回調(diào)的最后一個(gè)參數(shù)是future對象,通過該對象可以獲取協(xié)程返回值。如果回調(diào)需要多個(gè)參數(shù),可以通過偏函數(shù)導(dǎo)入。
import time
import asyncio
async def task(x):
print('Waiting: ', x)
await asyncio.sleep(x)
return 'Done after {}s'.format(x)
def callback(future):
print('Callback: ', future.result())
coroutine = task(2)
loop = asyncio.get_event_loop()
task = asyncio.ensure_future(coroutine)
task.add_done_callback(callback)
loop.run_until_complete(task)
coroutine執(zhí)行結(jié)束時(shí)候會(huì)調(diào)用回調(diào)函數(shù)。并通過參數(shù)future獲取協(xié)程執(zhí)行的結(jié)果。我們創(chuàng)建的task和回調(diào)里的future對象,實(shí)際上是同一個(gè)對象。
future 與 result
回調(diào)中我們使用了future對象的result方法。前面不綁定回調(diào)的例子中,我們可以看到task有fiinished狀態(tài)。在那個(gè)時(shí)候,可以直接讀取task的result方法。
async def task(x):
print('Waiting {}'.format(x))
return 'Done after {}s'.format(x)
coroutine = task(2)
loop = asyncio.get_event_loop()
task = asyncio.ensure_future(coroutine)
loop.run_until_complete(task)
# task.result()是協(xié)程對象的返回值
print('Task result: {}'.format(task.result()))
阻塞和await
使用async可以定義協(xié)程對象,使用await可以針對耗時(shí)的操作進(jìn)行掛起,就像生成器里的yield一樣,函數(shù)讓出控制權(quán)。協(xié)程遇到await,事件循環(huán)將會(huì)掛起該協(xié)程,執(zhí)行別的協(xié)程,直到其他的協(xié)程也掛起或者執(zhí)行完畢,再進(jìn)行下一個(gè)協(xié)程的執(zhí)行。
耗時(shí)的操作一般是一些IO操作,例如網(wǎng)絡(luò)請求,文件讀取等。我們使用asyncio.sleep函數(shù)來模擬IO操作。協(xié)程的目的也是讓這些IO操作異步化。
import asyncio
import time
async def task(x):
print('Waiting: ', x)
await asyncio.sleep(x)
return 'Done after {}s'.format(x)
start = time.time()
coroutine = task(2)
loop = asyncio.get_event_loop()
task = asyncio.ensure_future(coroutine)
loop.run_until_complete(task)
print('Task result: ', task.result())
print('Time: ', time.time() - start)
在 sleep的時(shí)候,使用await讓出控制權(quán)。即當(dāng)遇到阻塞調(diào)用的函數(shù)的時(shí)候,使用await方法將協(xié)程的控制權(quán)讓出,以便loop調(diào)用其他的協(xié)程。現(xiàn)在我們的例子就用耗時(shí)的阻塞操作了。
并發(fā)和并行
asyncio實(shí)現(xiàn)并發(fā),就需要多個(gè)協(xié)程來完成任務(wù),每當(dāng)有任務(wù)阻塞的時(shí)候就await,然后其他協(xié)程繼續(xù)工作。創(chuàng)建多個(gè)協(xié)程的列表,然后將這些協(xié)程注冊到事件循環(huán)中。
import asyncio
import time
async def task(x):
print('Waiting: ', x)
await asyncio.sleep(x)
return 'Done after {}s'.format(x)
start = time.time()
coroutine1 = task(1) #
coroutine2 = task(2)
coroutine3 = task(4)
loop = asyncio.get_event_loop()
tasks = [ # 創(chuàng)建任務(wù)
asyncio.ensure_future(coroutine1),
asyncio.ensure_future(coroutine2),
asyncio.ensure_future(coroutine3)
]
loop.run_until_complete(asyncio.wait(tasks))
for task in tasks:
print('Task result: ', task.result())
print('Time: ', time.time() - start)
# 當(dāng)任務(wù)比較多的時(shí)候,可以使用列表生成式,效果是一樣的。
import asyncio
import time
async def task(x):
print('Waiting: ', x)
await asyncio.sleep(x)
return 'Done after {}s'.format(x)
start = time.time()
loop = asyncio.get_event_loop()
tasks = [asyncio.ensure_future(task(i)) for i in [1,2,4]]
loop.run_until_complete(asyncio.wait(tasks))
for task in tasks:
print('Task result: ', task.result())
print('Time: ', time.time() - start)
使用aysncio實(shí)現(xiàn)了并發(fā)。asyncio.wait(tasks) 也可以使用 asyncio.gather(*tasks) ,前者接受一個(gè)task列表,后者接收一堆task。
總結(jié)
以上是生活随笔為你收集整理的python协成_Python协程(上)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 切割 字符串_web前端如何使用字符串
- 下一篇: c primer英文版第5版_2019足