# 這是學習廖雪峯老師python教程的學習筆記html
一、概覽python
asyncio是Python 3.4版本引入的標準庫,直接內置了對異步IO的支持web
asyncio的編程模型就是一個消息循環。咱們從asyncio模塊中直接獲取一個EventLoop的引用,而後把須要執行的協程扔到EventLoop中執行,就實現了異步IO。編程
1.一、asyncioio的關鍵字網絡
event_loop 事件循環:程序開啓一個無限循環,把一些函數註冊到事件循環上,當知足事件發生的時候,調用相應的協程函數併發
coroutine 協程:協程對象,指一個使用async關鍵字定義的函數,它的調用不會當即執行函數,而是會返回一個協程對象。協程對象須要註冊到事件循環,由事件循環調用。app
task 任務:一個協程對象就是一個原生能夠掛起的函數,任務則是對協程進一步封裝,其中包含了任務的各類狀態異步
future: 表明未來執行或沒有執行的任務的結果。它和task上沒有本質上的區別socket
async/await 關鍵字:python3.5用於定義協程的關鍵字,async定義一個協程,await用於掛起阻塞的異步調用接口。async
二、實例
2.一、用asyncio實現Hello world
import asyncio
@asyncio.coroutine # 把generator標記爲coroutine類型
def hello():
print("Hello world!")
r = yield from asyncio.sleep(1) # 異步調用asyncio.sleep(1)
print("Hello again!")
loop = asyncio.get_event_loop() # 建立消息事件,開啓了事件循環
loop.run_until_complete(hello()) # 將協程對象註冊到事件循環,由事件循環調用
loop.close() # 關閉事件
把asyncio.sleep(1)當作是一個耗時1秒的IO操做,在此期間,主線程並未等待,而是去執行EventLoop中其餘能夠執行的coroutine了,所以能夠實現併發執行。
由於loop裏只有一個事件【hello()】,因此會暫停1秒,打印「hello again」
2.二、用Task封裝兩個coroutine
import threading
import asyncio
@asyncio.coroutine # 把generator標記爲coroutine類型
def hello():
print('Hello world! (%s)' % threading.currentThread()) # 打印當前線程號
yield from asyncio.sleep(1)
print('Hello again! (%s)' % threading.currentThread())
loop = asyncio.get_event_loop()
tasks = [hello(), hello()] # 定義任務
loop.run_until_complete(asyncio.wait(tasks)) #asyncio.wait()等待子進程終止
loop.close() # 關閉消息事件
# 執行過程
Hello world! (<_MainThread(MainThread, started 140735195337472)>)
Hello world! (<_MainThread(MainThread, started 140735195337472)>)
(暫停約1秒)
Hello again! (<_MainThread(MainThread, started 140735195337472)>)
Hello again! (<_MainThread(MainThread, started 140735195337472)>)
# 解析
這裏的loop裏有兩個hello事件,下面簡稱h1和h2。
首先h1被執行,打印了"Hello world",異步執行了asyncio.sleep(1),須要暫停1秒
loop不會等待,將h1掛起,直接執行h2,又打印了"Hello world",而後又碰到asyncio.sleep(1),須要暫停1秒
1秒後,再次執行h1和h2,由於CPU處理速度很快,因此雖然h2比h1晚暫停,可是幾乎感受不到
2.3、用asyncio的異步網絡鏈接來獲取sina、sohu和163的網站首頁
import asyncio
@asyncio.coroutine # 把generator標記爲coroutine類型
def wget(host):
print('wget %s...' % host)
connect = asyncio.open_connection(host, 80) #建立異步鏈接
reader, writer = yield from connect #異步調用connect,返回reader,writer兩個實例,這是固定的兩個實例
header = 'GET / HTTP/1.0\r\nHost: %s\r\n\r\n' % host # 設置header
writer.write(header.encode('utf-8'))
yield from writer.drain() # 將設置的header寫入connect
while True:
line = yield from reader.readline() #讀取返回的HTTP
if line == b'\r\n':
break
print('%s header > %s' % (host, line.decode('utf-8').rstrip()))
# Ignore the body, close the socket
writer.close()
loop = asyncio.get_event_loop()
tasks = [wget(host) for host in ['www.sina.com.cn', 'www.sohu.com', 'www.163.com']]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
# 執行結果
wget www.sohu.com...
wget www.sina.com.cn...
wget www.163.com...
(等待一段時間)
(打印出sohu的header)
www.sohu.com header > HTTP/1.1 200 OK
www.sohu.com header > Content-Type: text/html
...
(打印出sina的header)
www.sina.com.cn header > HTTP/1.1 200 OK
www.sina.com.cn header > Date: Wed, 20 May 2015 04:56:33 GMT
...
(打印出163的header)
www.163.com header > HTTP/1.0 302 Moved Temporarily
www.163.com header > Server: Cdn Cache Server V2.0
3個鏈接由一個線程經過coroutine併發完成
3、小結
asyncio提供了完善的異步IO支持;
異步操做須要在coroutine中經過yield from完成;
多個coroutine能夠封裝成一組Task而後併發執行。
4、擴展文檔
python中重要的模塊--asyncio (http://www.javashuo.com/article/p-okfxrbuu-c.html)
python yield 與 yield from (https://blog.csdn.net/chenbin520/article/details/78111399?locationNum=7&fps=1)