您好,登錄后才能下訂單哦!
?
目錄
asyncio. 1
事件循環:... 1
協程:... 2
aiohttp:... 4
?
?
?
異步io,3.4version加入標準庫;
asyncio底層基于selectors實現,看似庫,其實是個框架,包含異步IO、事件循環、協程、任務等內容;
?
例:
def a():
??? for x in range(3):
??????? time.sleep(0.001)?? #生產上不能加此句,僅在多線程下做實驗用
??????? print('a.x', x)
?
def b():
??? for x in 'abc':
??????? time.sleep(0.001)
??????? print('b.x', x)
?
# a()?? #串行,兩件事如果有因果關系才需要串行,否則并行要好
# b()
?
# threading.Thread(target=a).start()?? #多線程下,由OS控制;輸出會亂
# threading.Thread(target=b).start()
?
if __name__ == '__main__':
??? multiprocessing.Process(target=a).start()?? #真正的同時進行,由OS控制
??? multiprocessing.Process(target=b).start()
?
?
是asyncio提供的核心運行機制;
?
loop = asyncio.get_event_loop()?? #返回一個事件循環對象,是asyncio.BaseEventLoop的實例;
loop.stop()、asyncio.AbstractEventLoop.stop()?? #停止運行事件循環
loop.run_forever()、asyncio.AbstractEventLoop.run_forever()?? #一直運行,直到stop
loop.run_until_complete(future)、asyncio.AbstractEventLoop.run_until_complete(future)?? #運行直至Future對象運行完
loop.close()、asyncio.AbstractEventLoop.close()?? #關閉事件循環
loop.is_running()、asyncio.AbstractEventLoop.is_running()?? #返回事件循環是否運行
?
?
例:
協程,有返回值None,但沒有用;
由自己控制(類似于并發的控制),與多線程、多進程沒關系;
在線程內通過生成器完成了調度,讓兩個函數幾乎都有在執行,這樣的調度不是OS的進程、線程完成的,而是用戶自己設計的;
編寫此程序,要使用yield來讓出控制權,要用循環幫助執行;
def a():
??? for x in range(3):
??????? time.sleep(0.001)
??????? print('a.x', x)
??????? yield
?
def b():
??? for x in 'abc':
??????? time.sleep(0.001)
??????? print('b.x', x)
??????? yield
?
m = a()
n = b()
for _ in range(3):
??? next(m)
??? next(n)
?
不是進程,也不是線程,它是用戶空間調度完成并發處理的方式;
進程、線程由OS完成調度,而協程是線程內完成調度,它不需要更多的線程,自然也沒有多線程切換帶來的開銷;
協程是非搶占式調度(串行),只有一個協程主動讓出控制權,另一個協程才會被調度;
協程也需要使用鎖機制,因為是在同一個線程中執行;
多cpu下,可使用多進程+協程配合,既能進程并發又能發揮協程在單線程中的優勢;
py中協程是基于生成器的;
?
3.5version開始,py提供關鍵字async、await,在語言上原生支持協程,支持async def、async with、async for;
async def用來定義協程函數,調用后即是協程對象(同生成器函數、生成器對象),協程函數中可以不包含await、async關鍵字,不能使用yield關鍵字;
?
asyncio.iscoroutinefunction(sleep)?? #判斷是否是協程函數
asyncio.iscoroutine(thread)?? #判斷是否是協程對象
?
例:
@asyncio.coroutine?? #使用裝飾器,3.4ver用法
def sleep(x):?? #生成器+函數(函數中有yield語句即為生成器函數)
??? for i in range(3):?? #有循環
??????? print('sleep {}'.format(i))
??????? yield from asyncio.sleep(x)?? #asyncio.sleep(x),另一個生成器對象
?
loop = asyncio.get_event_loop()
loop.run_until_complete(sleep(10))?? #sleep(3)必須要有括號,sleep為生成器函數,可理解為拿到生成器對象,用返回的對象循環
loop.close()
?
例:
async def sleep(x):?? #3.5ver用法
??? 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(x)
?
loop = asyncio.get_event_loop()
tasks = [sleep(3), showthread(3)]?? #放協程對象
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
?
print(asyncio.iscoroutinefunction(sleep))
print(asyncio.iscoroutine(showthread))
輸出:
[<_MainThread(MainThread, started 19172)>]
sleep 0
[<_MainThread(MainThread, started 19172)>]
sleep 1
[<_MainThread(MainThread, started 19172)>]
sleep 2
True
False
?
例:
TcpEchoServer
?
?
>pip install aiohttp
?
對于socket,在accept()后,關鍵是recv()和send();
對于http,關鍵是request和response;
?
異步的好處:
沒有多線程,并發用多進程;
多進程 + 協程,可完成很高的并發;
?
簡單函數-->多線程-->IO復用-->異步io;
?
例,服務端:
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(status=200,text=request.match_info.get('id', '0000'))
?
app = web.Application()
app.router.add_get('/', indexhandle)
app.router.add_get('/{id}', handle)
web.run_app(app, host='0.0.0.0', port=9999)
輸出:
======== Running on http://0.0.0.0:9999 ========
(Press CTRL+C to quit)
<MatchInfo {'id': '555'}: <ResourceRoute [GET] <DynamicResource? /{id}> -> <function handle at 0x00000000039989D8>>
?
?
例,客戶端:
from aiohttp import ClientSession
import asyncio
?
async def get_html(url: str):
??? async with ClientSession() as session:?? #client與server建立會話
??????? async with session.get(url) as res:?? #response
??????????? print(res.status)
??????????? print(await res.text())
?
url = 'http://127.0.0.1:9999/555'?? #服務端
?
loop = asyncio.get_event_loop()
loop.run_until_complete(get_html(url))?? #爬蟲的第一步,拿到html頁面數據后,用第三方庫解析html變成dom樹,拿到想要的東西
loop.close()
輸出:
200
555
?
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。