前言
在了解了Python并發程式設計的多線程和多程序之後,我們來了解一下基于asyncio的異步IO程式設計 => 協程

協程
協程(Coroutine)又稱微線程、纖程,協程不是程序或線程,其執行過程類似于 Python 函數調用,Python 的 asyncio 子產品實作的異步IO程式設計架構中,協程是對使用 async 關鍵字定義的異步函數的調用
一個程序包含多個線程,類似于一個人體組織有多種細胞在工作,同樣,一個程式可以包含多個協程。多個線程相對獨立,線程的切換受系統控制。同樣,多個協程也相對獨立,但是其切換由程式自己控制
那協程有什麼優勢呢?
- 執行效率極高,因為子程式切換(函數)不是線程切換,由程式自身控制,沒有切換線程的開銷。是以與多線程相比,線程的數量越多,協程性能的優勢越明顯
- 不需要多線程的鎖機制,因為隻有一個線程,也不存在同時寫變量沖突,在控制共享資源時也不需要加鎖,是以執行效率高很多
Python3.x協程
Python3.x還提供了如下方式實作協程:asyncio + yield from (python3.4+) asyncio + async/await (python3.5+)
Python3.4以後引入了asyncio子產品,可以很好的支援協程
asyncio
evnt_loop: 事件循環,相當于一個無限循環,我們可以把一些函數注冊到這個事件循環上,當滿足條件發生的時候,就會調用對應的處理方法
coroutine: 中文翻譯叫協程,在 Python 中常指代為協程對象類型,我們可以将協程對象注冊到時間循環中,它會被事件循環調用。我們可以使用 async 關鍵字來定義一個方法,這個方法在調用時不會立即被執行,而是傳回一個協程對象
task: 任務,它是對協程對象的進一步封裝,包含了任務的各個狀态
future: 代表将來執行或沒有執行的任務的結果,實際上和 task 沒有本質差別
async
定義異步函數
async def async_function():
print('Number:', 1)
return 1
print(async_function())
輸出:
傳回一個協程對象
<coroutine object async_function at 0x10a4b0f10>
複制
調用send方法激活
print(async_function().send(None))
複制
異步函數
async def async_function():
print('Number:', 1)
r = requests.get('http://www.baidu.com')
return r
coroutine = async_function()
loop = asyncio.get_event_loop()
t = loop.run_until_complete(coroutine)
print(t)
print('After calling loop')
複制
異步函數task
coroutine = async_function()
loop = asyncio.get_event_loop()
task = loop.create_task(coroutine)
print('Task:', task)
loop.run_until_complete(task)
print('Task:', task)
print('After calling loop')
輸出: coroutine 對象多了運作狀态,比如 running、finished 等
Task: <Task pending coro=<async_function() running at async_t.py:104>>
Number: 1
Task: <Task finished coro=<async_function() done, defined at async_t.py:104> result=<Response [200]>>
After calling loop
複制
異步函數ensure_future
task = asyncio.ensure_future(coroutine)
print('Task:', task)
loop = asyncio.get_event_loop()
loop.run_until_complete(task)
print('Task:', task)
print('After calling loop')
複制
異步函數綁定回調
async def async_function():
print('Number:', 1)
r = requests.get('http://www.baidu.com')
return r
def callback(task):
print('Status:', task.result())
task = asyncio.ensure_future(coroutine)
task.add_done_callback(callback)
print('Task:', task)
loop = asyncio.get_event_loop()
loop.run_until_complete(task)
print('Task:', task)
複制
異步函數網絡并發執行
import requests_async as requests
async def post_requests():
print("Hello world!")
async with requests.Session() as session:
print("create Session statr")
response = await session.get('https://example.org')
print("create Session over")
print(response.status_code)
# print(response.text)
tasks = [post_requests() for host in ['www.sina.com.cn', 'www.sohu.com', 'www.163.com']]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
print('Task:', tasks)
複制
異步函數網絡請求
async def get(url):
return requests.get(url)
async def request():
url = 'http://127.0.0.1:5000/api'
print('Waiting for', url)
response = await get(url)
print('Get response from', url, 'Result:', response.text)
tasks = [asyncio.ensure_future(request()) for _ in range(5)]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
複制
多任務異步
import asyncio
import requests
async def request():
url = 'https://www.baidu.com'
status = requests.get(url)
return status
tasks = [asyncio.ensure_future(request()) for _ in range(5)]
print('Tasks:', tasks)
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
for task in tasks:
print('Task Result:', task.result())
複制
aiohttp異步請求
async def aiohttp_get():
url = 'http://127.0.0.1:5000/api'
print('Waiting for', url)
session = aiohttp.ClientSession()
response = await session.get(url)
result = await response.text()
print('Get response from', url)
session.close()
return result
tasks = [asyncio.ensure_future(aiohttp_get()) for _ in range(5)]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
複制
結尾
上面就是python協程的一些簡單體驗,後續會結合一些協程實戰項目,分享更多使的技巧~