python異步IO的項(xiàng)目實(shí)踐
asyncio是python3.4引入的標(biāo)準(zhǔn)庫,內(nèi)置對(duì)異步IO的支持。asyncio的編程模型是一個(gè)消息循環(huán),從asyncio模塊中直接獲取一個(gè)EventLoop的引用,然后把需要執(zhí)行的協(xié)程放入EventLoop中執(zhí)行,就實(shí)現(xiàn)了異步IO。
協(xié)程又稱為微線程。子程序在所有語言中都是層級(jí)調(diào)用,子程序調(diào)用通過棧實(shí)現(xiàn)。一個(gè)線程就是執(zhí)行一個(gè)子程序。協(xié)程最大的優(yōu)勢(shì)是執(zhí)行效率高,子程序切換不是線程切換,而是由程序自身控制。第二個(gè)優(yōu)勢(shì)是不需要多線程的鎖機(jī)制。python對(duì)協(xié)程的支持通過generator實(shí)現(xiàn),generator中,可以通過for循環(huán)來迭代,也可以不斷調(diào)用next()函數(shù)獲取由yield語句返回的下一個(gè)值。
協(xié)程示例,@asyncio.coroutine把一個(gè)生成器標(biāo)記為coroutine類型,自python3.8棄用,使用async def替代。
import threading import asyncio @asyncio.coroutine def hello(): ? ? print('Hello World! (%s)' % threading.current_thread()) ? ? # yield from調(diào)用另一個(gè)生成器 ? ? r = yield from asyncio.sleep(1) ? ? print('Hello Again! (%s)' % threading.current_thread()) loop = asyncio.get_event_loop() # 兩個(gè)協(xié)程是由同一個(gè)線程并發(fā)執(zhí)行的 tasks = [hello(), hello()] loop.run_until_complete(asyncio.wait(tasks)) loop.close()
結(jié)果:
Hello World! (<_MainThread(MainThread, started 49300)>)
Hello World! (<_MainThread(MainThread, started 49300)>)
Hello again! (<_MainThread(MainThread, started 49300)>)
Hello again! (<_MainThread(MainThread, started 49300)>)
推薦使用async/await語法編寫協(xié)程應(yīng)用。
# 直接調(diào)用main()并不會(huì)執(zhí)行協(xié)程應(yīng)用。 >>> import asyncio >>> async def main(): ... print('hello') ... await asyncio.sleep(1) ... print('world') >>> asyncio.run(main()) hello world
傳統(tǒng)生產(chǎn)消費(fèi)模型,一個(gè)線程寫消息,一個(gè)線程讀消息,通過鎖機(jī)制控制隊(duì)列和等待,但一不小心就可能死鎖。改用協(xié)程生產(chǎn)消息后直接通過yield跳轉(zhuǎn)到消費(fèi)者開始執(zhí)行,待消費(fèi)者執(zhí)行完畢后,切換回生產(chǎn)者,效率極高。
# consumer函數(shù)是一個(gè)生成器 def consumer(): ? ? r = '' ? ? while True: ? ? ? ? n = yield r ? ? ? ? if not n: ? ? ? ? ? ? return? ? ? ? ? print('[COUSUMER] Consuming %s...' % n) ? ? ? ? r = '200 OK' def produce(c): ? ? # 啟動(dòng)生成器 ? ? c.send(None) ? ? n = 0 ? ? while n < 5: ? ? ? ? n = n + 1 ? ? ? ? print('[PRODUCER] Producing %s...' % n) ? ? ? ? r = c.send(n) ? ? ? ? print('[PRODUCER] Consumer return:%s' % r) ? ? c.close() # 注意到consumer函數(shù)是一個(gè)generator,把一個(gè)consumer傳入produce后: # 首先調(diào)用c.send(None)啟動(dòng)生成器; # 然后,一旦生產(chǎn)了東西,通過c.send(n)切換到consumer執(zhí)行; # consumer通過yield拿到消息處理,又通過yield把結(jié)果傳回; # produce拿到consumer處理的結(jié)果,繼續(xù)生產(chǎn)下一條消息; # produce決定不生產(chǎn)了,通過c.close()關(guān)閉consumer,整個(gè)過程結(jié)束。 # 整個(gè)流程無鎖,由一個(gè)線程執(zhí)行,produce和consumer協(xié)作完成任務(wù),所以稱為“協(xié)程”,而非線程的搶占式多任務(wù)。 ? ? c = consumer() produce(c)
asyncio可以實(shí)現(xiàn)單線程并發(fā)IO操作,用單線程+coroutine實(shí)現(xiàn)多用戶的高并發(fā)支持,asyncio實(shí)現(xiàn)了TCP、UDP、SSL等協(xié)議,aiohttp則是基于asyncio實(shí)現(xiàn)的HTTP框架。
import asyncio from aiohttp import web def index(request): ? ? return web.Response(body=b'<h1>Index</h1>') def hello(request): ? ? yield from asyncio.sleep(0.5) ? ? text = '<h1>Hello, %s!</h1>' % request.match_info['name'] ? ? return web.Response(body=text.encode('utf-8')) @asyncio.coroutine def init(loop): ? ? app = web.Application(loop=loop) ? ? app.router.add_route('GET', '/', index) ? ? app.router.add_router('GET', '/hello/{name}', hello) ? ? srv = yield from loop.create_server(app.make_handler(), '127.0.0.1', 8000) ? ? print('Server started at http://127.0.0.1:8000') ? ? return srv loop = asyncio.get_event_loop() loop.run_until_complete(init(loop)) loop.run_forever()
到此這篇關(guān)于python異步IO的項(xiàng)目實(shí)踐的文章就介紹到這了,更多相關(guān)python異步IO內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python操作列表常用方法實(shí)例小結(jié)【創(chuàng)建、遍歷、統(tǒng)計(jì)、切片等】
這篇文章主要介紹了Python操作列表常用方法,結(jié)合實(shí)例形式總結(jié)分析了Python列表常見的創(chuàng)建、遍歷、統(tǒng)計(jì)、切片等操作技巧與相關(guān)注意事項(xiàng),需要的朋友可以參考下2019-10-10Python實(shí)現(xiàn)的用戶登錄系統(tǒng)功能示例
這篇文章主要介紹了Python實(shí)現(xiàn)的用戶登錄系統(tǒng)功能,涉及Python流程控制及字符串判斷等相關(guān)操作技巧,需要的朋友可以參考下2018-02-02