天天看點

python協程初體驗

前言

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

python協程初體驗

協程

協程(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協程的一些簡單體驗,後續會結合一些協程實戰項目,分享更多使的技巧~