python2中的gevent通過協(xié)程已經(jīng)實現(xiàn)了異步IO,python3中專門有一個模塊來處理異步IO珊泳,ascyio模塊。
先看一個列子:
import asyncio
import datetime
import time
@asyncio.coroutine
def hello():
print('任務(wù)一 開始了!')
print('執(zhí)行中')
print('遇到了費時操作')
r = yield from asyncio.sleep(5)
print(str(r))
print('任務(wù)一 費事操作做完了')
print('任務(wù)一繼續(xù)')
@asyncio.coroutine
def hello2():
print('任務(wù)二 開始了!')
print('執(zhí)行中')
print('遇到了費時操作')
r = yield from asyncio.sleep(5)
print('任務(wù)二費事操作做完了')
print('任務(wù)二繼續(xù)')
start=datetime.datetime.now()
loop=asyncio.get_event_loop()
task = [hello(),hello2()]
loop.run_until_complete(asyncio.wait(task))
loop.close()
print(datetime.datetime.now()-start)
運行結(jié)果:
任務(wù)二 開始了!
執(zhí)行中
遇到了費時操作
任務(wù)一 開始了!
執(zhí)行中
遇到了費時操作
任務(wù)二費事操作做完了
任務(wù)二繼續(xù)
None
任務(wù)一 費事操作做完了
任務(wù)一繼續(xù)
0:00:05.003013
從運行結(jié)果看,效果和gevent是一樣的综慎,即遇到費時操作直接跳到另一個協(xié)程里,直到io結(jié)束跳回來好港。
具體實現(xiàn)步驟:
- 用@asyncio.coroutine將一個生成器函數(shù)變?yōu)閏orutine對象
- yield from 表示等待一個費時操作返回結(jié)果
- 創(chuàng)建loop,將任務(wù)添加進去
- 運行l(wèi)oop
實際問題中并不會出現(xiàn)sleep這樣的費時丈探,async中也封裝了各種的io操作拔莱,使其支持協(xié)程。
下面是對網(wǎng)絡(luò)io的例子:
``` stylus
import asyncio
@asyncio.coroutine
def get_hearder(url):
print('正在連接%s'%url)
connect = asyncio.open_connection(url,80)
print('connect is %s'%connect)
reader,writer = yield from connect
header = 'GET / HTTP/1.0\r\nHost: %s\r\n\r\n' %url
writer.write(header.encode('utf8'))
print('正在發(fā)送請求')
yield from writer.drain()#沖洗緩存區(qū)讼渊,不知道啥意思尊剔,大概是發(fā)送請求把,請指正
while True:
print('正在獲取數(shù)據(jù)%s'%url)
line = yield from reader.readline()
if line == b'\r\n':
break
print('%s header > %s' % (url, line.decode('utf-8').rstrip()))
writer.close()#關(guān)閉連接
loop = asyncio.get_event_loop()
tasks = [ get_hearder(url) for url in (
'www.baidu.com',
'www.souhu.com',
'www.soso.com', # asyncio.open_connection的參數(shù)為host,不需要加http
)]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
運行結(jié)果:
``` stylus
正在連接www.souhu.com
connect is <generator object open_connection at 0x000001B45A1E94C0>
正在連接www.baidu.com
connect is <generator object open_connection at 0x000001B45A1E9620>
正在連接www.soso.com
connect is <generator object open_connection at 0x000001B45A1E97D8>
正在發(fā)送請求
正在獲取數(shù)據(jù)www.baidu.com
www.baidu.com header > HTTP/1.1 200 OK
正在獲取數(shù)據(jù)www.baidu.com
www.baidu.com header > Date: Fri, 21 Jul 2017 06:23:40 GMT
正在獲取數(shù)據(jù)www.baidu.com
www.baidu.com header > Content-Type: text/html
正在獲取數(shù)據(jù)www.baidu.com
www.baidu.com header > Content-Length: 14613
正在獲取數(shù)據(jù)www.baidu.com
www.baidu.com header > Last-Modified: Wed, 28 Jun 2017 02:16:00 GMT
正在獲取數(shù)據(jù)www.baidu.com
www.baidu.com header > Connection: Close
正在獲取數(shù)據(jù)www.baidu.com
www.baidu.com header > Vary: Accept-Encoding
正在獲取數(shù)據(jù)www.baidu.com
www.baidu.com header > Set-Cookie: BAIDUID=B275DA6992F2400B0505F9244F6FD742:FG=1; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
正在獲取數(shù)據(jù)www.baidu.com
www.baidu.com header > Set-Cookie: BIDUPSID=B275DA6992F2400B0505F9244F6FD742; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
正在獲取數(shù)據(jù)www.baidu.com
www.baidu.com header > Set-Cookie: PSTM=1500618220; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
正在獲取數(shù)據(jù)www.baidu.com
www.baidu.com header > P3P: CP=" OTI DSP COR IVA OUR IND COM "
正在獲取數(shù)據(jù)www.baidu.com
www.baidu.com header > Server: BWS/1.1
正在獲取數(shù)據(jù)www.baidu.com
www.baidu.com header > X-UA-Compatible: IE=Edge,chrome=1
正在獲取數(shù)據(jù)www.baidu.com
www.baidu.com header > Pragma: no-cache
正在獲取數(shù)據(jù)www.baidu.com
www.baidu.com header > Cache-control: no-cache
正在獲取數(shù)據(jù)www.baidu.com
www.baidu.com header > Accept-Ranges: bytes
正在獲取數(shù)據(jù)www.baidu.com
正在發(fā)送請求
正在獲取數(shù)據(jù)www.soso.com
www.soso.com header > HTTP/1.1 302 Moved Temporarily
正在獲取數(shù)據(jù)www.soso.com
www.soso.com header > Server: nginx
正在獲取數(shù)據(jù)www.soso.com
www.soso.com header > Date: Fri, 21 Jul 2017 06:23:40 GMT
正在獲取數(shù)據(jù)www.soso.com
www.soso.com header > Content-Type: text/html
正在獲取數(shù)據(jù)www.soso.com
www.soso.com header > Content-Length: 154
正在獲取數(shù)據(jù)www.soso.com
www.soso.com header > Connection: close
正在獲取數(shù)據(jù)www.soso.com
www.soso.com header > Location: http://www.sogou.com/?rfrom=soso
正在獲取數(shù)據(jù)www.soso.com
www.soso.com header > Expires: Fri, 21 Jul 2017 06:23:40 GMT
正在獲取數(shù)據(jù)www.soso.com
www.soso.com header > Cache-Control: max-age=0
正在獲取數(shù)據(jù)www.soso.com
正在發(fā)送請求
正在獲取數(shù)據(jù)www.souhu.com
www.souhu.com header > HTTP/1.1 301 Moved Permanently
正在獲取數(shù)據(jù)www.souhu.com
www.souhu.com header > Server: Tengine/1.4.2
正在獲取數(shù)據(jù)www.souhu.com
www.souhu.com header > Date: Fri, 21 Jul 2017 06:23:39 GMT
正在獲取數(shù)據(jù)www.souhu.com
www.souhu.com header > Content-Type: text/html
正在獲取數(shù)據(jù)www.souhu.com
www.souhu.com header > Content-Length: 286
正在獲取數(shù)據(jù)www.souhu.com
www.souhu.com header > Connection: close
正在獲取數(shù)據(jù)www.souhu.com
www.souhu.com header > Location: http://127.0.0.1/
正在獲取數(shù)據(jù)www.souhu.com
運行結(jié)果里京痢,貌似asycio只把連接當成了費時操作,其他部分都同步了臭家,不知是不是時間太短而忽略掉了吭产,或者是有特殊的調(diào)度方法鸭轮。
總結(jié)
async封裝了異步io操作,使用它可以方便的用單線程的協(xié)程方式實現(xiàn)異步io