1.什麼是coroutinehtml
coroutine,最先我是在lua裏面看到的,coroutine最大的好處是能夠保存堆棧,讓程序得以繼續執行,在python裏面,通常是利用yield來實現,具體能夠看以下文章:python
http://www.cnblogs.com/tqsummer/archive/2010/12/27/1917927.htmlwindows
python中的yield以及yield from語法可讓程序支持coroutine服務器
2.asyncio庫異步
Python3中,提供了基於coroutine的異步IO庫,就是asynciosocket
https://docs.python.org/3/library/asyncio.htmlasync
2.1 event looptcp
asyncio庫一個重要的概念就是事件循環,只有啓動事件循環之後,纔可讓coroutine任務得以繼續執行,若是event loop中止或者暫停,那麼整個異步io也中止或者暫停,相似於操做系統的事件循環機制函數
asyncio的內部是基於selector(也多是epoll)或者windows iocp來實現的,這也是爲何須要啓動一個event loop,event loop能夠當作是對各個平臺的異步IO"等待"這個操做的封裝工具
2.2 asyncio庫
cotoutine
coroutine即爲一個支持寫成的函數,能夠利用iscoroutinefunction來判斷是否coroutine函數,這個函數須要@asyncio.coroutine來修飾
利用@asyncio.coroutine修飾之後,這個函數能夠支持await(python 3.5) 或者 yield from語法,一旦執行yield from 語法之後,asyncio將會掛起當前的coroutine,去執行其餘的coroutine
以下代碼:
當開始運行event loop之後
1.開始執行sleep3s
2.當程序開始進入睡眠之後,event loop不會中止當前線程,而是掛起當前函數,執行下一個coroutine,即sleep5s
3.sleep5s開始進入睡眠,掛起當前的函數
4.event loop檢測到sleep 3s時間已經到了,因而從新執行被掛起的sleep3s,sleep3s執行完畢
5.sleep5s時間已經到了,因而從新執行被掛起的sleep5s,sleep5s執行完畢
基於coroutine的服務器
如上圖,_tcp_listen建立了一個tcp 服務器,而且收到一個tcp連接之後,建立一個_tcp_recv的任務,而後開始監聽tcp鏈接的數據
與基於回調的庫區別
coroutine版本代碼在recv上邏輯處理代碼是線性的而不是斷裂的,基於回調的代碼則常常須要亂跳,可讀性較高
並且不用建立臨時的數據去保存一些變量,上圖中的self.tcp_clients就是由於老版本是基於回調的,須要這個數據成員去存儲(懶得再本身從新寫代碼,這分是重構某個工具到通常時候的代碼)
擴展asyncio
由於項目裏面須要知道對方udp的地址,所以須要擴展sock_recv,利用socket自己提供的recv_from
看了下loop.socket_recv的源碼,loop.socket_recv的
在調用以前 必須將socket設置爲非阻塞,不然會報錯
關鍵點在於add_reader這個函數將socket傳送給異步IO(默認是selector),而且傳送一個回調進去(在這個例子裏面是_sock_recv本身這個函數,只要有數據能夠讀取之後,將會再次調用_sock_recv這個函數
asyncio也不止支持sleep以及io操做,還支持多進程,lock等操做
只要將上圖的data = sock.recv(n)改成data, addr = sock.recv_from(n)就能夠了
在3.5中,新增長了async以及await的語法,用於代替asynio.coroutine以及yield from
Python3.5 的async以及await