Python中asyncio庫的使用

一、asyncio

3.4版本之後加入標準庫。html

Asyncio底層基於selectors,看似庫,其實就是框架,包含異步IO、時間循環、協程、任務等內容。web

def a(x=3):
    for x in range(x):
        print(x)

def b(x=3):
    for x in range(x):
        print(x)

a()
b()

上例子中函數調用是串行,不是並行。能夠利用方法進行改變。chrome

 

1)利用生成器函數session

def a(x=3):
    for x in range(x):
        print(x)
        yield

def b(x=3):
    for x in range(x):
        print(x)
        yield

x1 = a()
y = b()
for i in range(3):
    next(x1)
    next(y)

 

2)多線程多線程

import time
import threading


def a(x=3):
    for x in range(x):
        time.sleep(1)
        print(x)

def b(x=3):
    for x in range(x):
        time.sleep(1)
        print(x)

threading.Thread(target=a,name='a').start()
threading.Thread(target=b,name='b').start()

3)利用multiprocessing庫,也是多線程併發

import time
import multiprocessing

def a(x=3):
    for x in range(x):
        time.sleep(1)
        print(x)

def b(x=3):
    for x in range(x):
        time.sleep(1)
        print(x)

if __name__ == '__main__':
   
    multiprocessing.Process(target=a,name='a').start()
    multiprocessing.Process(target=b,name='b').start()

 

 

生成器函數,真並行。app

 

生成器在用戶空間完成的切換。調度不是操做系統的進程、線程。兩個函數都有機會執行。框架

Yield本意是讓出,讓出線程執行的權限,讓出控制權限。異步

必須有循環,沒有循環就不可以交替執行。async

 

二、事件循環

事件循環是asyncio提供的核心運行機制。

Column

Column

Asyncio.get_event_loop()

返回一個事件循環對象,是asyncio.Baseeventloop的實例

Abstracteventloop.stop()

中止運行事件循環

Abstracteventloop.run_forever()

一直運行直到stop()

Abstracteventloop.run_until_complete(future)

運行直至future對象運行完

Abstracteventloop.close()

關閉事件循環

Abstracteventloop.is_running()

返回事件循環的是否運行

 

 

三、協程

 

1)不是進程,也不是線程,是用戶空間調度的完成併發處理的方式。是在用戶空間內部完成的。

 

2)進程、線程是操做系統完成調度,而協程是線程內完成調度,不須要更多的線程,也沒有多線程切換帶來的開銷。

 

3)協程是非搶佔式調度,只有協程主動讓出控制權,另外一個協程纔會被調度。

 

4)協程不須要使用鎖機制,由於是在同一個線程中執行的。

 

5)多CPU下,可使用多進程和協程配合下,既能進程並行又能發揮協程在單線程中的優點。

 

6)Python中協程是基於生成器的。

 

 

線程和進程是操做系統內完成的。

 

四、協程的使用

 

Coroutine協程;

 

await:等待,至關於yield form。

 

import asyncio
@asyncio.coroutine
def sleep(x):
    for i in range(3):
        print('sleep {}'.format(i))
        yield from asyncio.sleep(3)

loop = asyncio.get_event_loop()
loop.run_until_complete(sleep(3))
loop.close()

將生成器函數轉換爲協程函數,就能夠在循環中執行了。

 

 

3.5版本後,Python提供關鍵字async,await,在語言上原生支持協程。

import asyncio
async def sleep(x):
    for i in range(3):
        print('sleep{}'.format(i))
        await asyncio.sleep(x)

loop = asyncio.get_event_loop()
loop.run_until_complete(sleep(3))
loop.close()

 

sleep 0

sleep 1

sleep 2

 

Async 得分用來定義協程函數,iscoroutinefunction()返回True,協程函數中能夠不包含await,async關鍵字,但不能上使用yield關鍵字。

如同生成器函數調用返回生成器對象同樣,協程函數調用也會返回一個對象成爲協程對象,iscoroutine()返回True。

import asyncio
import threading


async def sleep(x):
    for i in range(3):
        print('sleep{}'.format(i))
        await asyncio.sleep(x)

async def showthread(x):
    for i in range(3):
        print(threading.enumerate())
        await asyncio.sleep(2)

loop = asyncio.get_event_loop()
tasks = [sleep(3),showthread(3)]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()

協程版本

import asyncio
import threading

@asyncio.coroutine
def a():
    for x in range(3):
        print('a.x',x)
        yield
@asyncio.coroutine
def b():
    for i in range(3):
        print('b.x',i)
        yield

print(asyncio.iscoroutinefunction(a))
print(asyncio.iscoroutinefunction(b))

loop = asyncio.get_event_loop()
tasks = [a(),b()]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()

 

 

 

Tasks,任務列表。

下面是執行的;

 

 

 

新的語法。

 

五、tcp echo server舉例

import asyncio


async def handle(reader,writer):
    while True:
        data = await reader.read(1024)
        print(dir(reader))
        print(dir(writer))
        client = writer.get_extra_info('peername')
        message = '{}you mesg {}'.format(client,data.decode()).encode()
        writer.writer(message)
        await writer.drain()

loop = asyncio.get_event_loop()
ip = '127.0.0.1'
port = 8080
crt = asyncio.start_server(handle,ip,port,loop=loop)
server = loop.run_until_complete(crt)
print(server)
try:
    loop.run_forever()
except KeyboardInterrupt:
    pass
finally:
    server.close()
    loop.close()

 

六、aiohttp  庫:

安裝pip install aiohttp

寫http服務。

http server

from aiohttp import web


async def indexhandle(request:web.Request):
    return web.Response(text=request.path,status=201)

async def handle(request:web.Request):
    print(request.match_info)
    print(request.query_string)
    return web.Response(text=request.match_info.get('id','0000'),status=200)

app = web.Application() #默認端口和地址。
app.router.add_get('/',indexhandle)   #請求來了找處理函數。
app.router.add_get('/{id}',handle)

web.run_app(app,host='127.0.0.1',port=8080)

 

======== Running on http://127.0.0.1:8080 ========

(Press CTRL+C to quit)

<MatchInfo {'id': 'favicon.ico'}: <ResourceRoute [GET] <DynamicResource  /{id}> -> <function handle at 0x00000044F1494730>>

 

 

import asyncio
from aiohttp import ClientSession


async def get_html(url:str):
    async with ClientSession() as session:   #with是上下文
        async with session.get(url) as res:   #session是保持會話,get獲得一個網頁。
            print(res.status)   # 打印狀態碼
            print(await res.text())   #  提取文本內容。首頁都是同步加載,裏面異步加載請求。
           


url = 'http://www.magedu.com'

loop = asyncio.get_event_loop()
loop.run_until_complete(get_html(url))
loop.close()

 

200

<!DOCTYPE html>

<html lang="zh-CN">

<head>

    <meta charset="UTF-8">

    <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">

    <meta name="renderer" content="webkit">

    <meta name="viewport" content="initial-scale=1.0,user-scalable=no,maximum-scale=1,width=device-width">

    <meta name="format-detection" content="telephone=no">

相關文章
相關標籤/搜索