下面屬於協程的應用和以前剩下的沒寫詳細的。html
上篇說過了協程之間切換的開銷極小,用這個相對於threading的優點以及業務場景對比還有各類細分的對比能扯不少,我以爲在我目前的階段不須要太糾結這個python
即把這個當成threading的替代便可,asyncio能夠簡單認爲比threading併發量更大,內存開銷更小就好了(GIL平常先背個鍋)服務器
再說說簡單的用法,首先asyncio是一個消息循環,有什麼用呢?首先說一下協程工做完一段代碼以後要返回主線程,可是這時候可能主線程也在忙,而asyncio至關於併發
一個信箱,FIFO樣式的,協程工做完就把完成通知丟到「信箱」裏面去,供主線程有空的時候順序讀取以便安排新的任務。框架
看代碼:async
1 import threading 2 import asyncio 3 4 @asyncio.coroutine 5 def t1(): 6 print('去洗菜', threading.currentThread()) 7 yield from asyncio.sleep(5) 8 print('炒菜', threading.currentThread()) 9 10 @asyncio.coroutine 11 def t2(): 12 print('洗米', threading.currentThread()) 13 yield from asyncio.sleep(5) 14 print('煮飯', threading.currentThread()) 15 16 @asyncio.coroutine 17 def t3(): 18 print('洗衣服', threading.currentThread()) 19 yield from asyncio.sleep(5) 20 print('晾衣服', threading.currentThread()) 21 22 loop = asyncio.get_event_loop() 23 tasks = [t1(),t2(),t3()] 24 loop.run_until_complete(asyncio.wait(tasks)) 25 loop.close()
out: 去洗菜 <_MainThread(MainThread, started 7732)> 洗米 <_MainThread(MainThread, started 7732)> 洗衣服 <_MainThread(MainThread, started 7732)> 炒菜 <_MainThread(MainThread, started 7732)> 煮飯 <_MainThread(MainThread, started 7732)> 晾衣服 <_MainThread(MainThread, started 7732)>
@asyncio.coroutine 表面這是一個要扔到消息循環(loop)的協程。asyncio.get_event_loop()是建立一個消息循環,而後分配任務,執行任務並等待任務結束,關閉消息循環。這就是一個簡單的用法。ide
而後爲了簡化@asyncio.coroutine和yield from,從python3.5開始引入了async and await,使用方法就是用async替換掉@asyncio.coroutine,await替換掉yield from函數
async def t1(): print('去洗菜', threading.currentThread()) await asyncio.sleep(5) print('炒菜', threading.currentThread())
而後還有諸如綁定回調,協程嵌套等等其餘用法暫時參考http://www.javashuo.com/article/p-okfxrbuu-c.html,否則就等我後面的更新哈哈哈哈哈哈<( ̄︶ ̄)↗
oop
爲何寫這玩意兒呢,我隱隱以爲之後會用到它,因此先記下來。spa
這玩意兒是基於asyncio(就是上面那玩意兒)實現的HTTP框架,能夠實現單線程併發IO,主要用於服務器端。畢竟HTTP做爲一個IO操做開銷也是很大的呀
用以前就先得裝好pip install aiohttp或者在ananconda裏面點一點安裝
真的只是先記下來啊,待我之後再來一篇(¬_¬)
一個相似於其餘語言的線程池的概念,用的是multiprocessing,真正的並行計算。上面的協程只是僞並行計算。
首先要用到的東西concurrent.futures.Executor,裏面有兩個
ThreadPoolExecutor和ProcessPoolExecutor,建池子的時候要指定用哪一個,而後給裏面的max_workers這個參數安排一下數量,給幾個核幹活。
而後用submit提交任務和任務參數,submit(fn, args, kwargs),而後done執行,result獲取結果。
1 from concurrent.futures import ThreadPoolExecutor 2 import time 3 4 5 def task(msg): 6 time.sleep(5) 7 return msg 8 9 10 # 建立一個線程池 11 pool = ThreadPoolExecutor(max_workers=2) 12 13 # 往線程池加入2個task 14 t1 = pool.submit(task, 'hello') 15 t2 = pool.submit(task, 'world') 16 17 print(t1.done()) 18 time.sleep(5) 19 print(t2.done()) 20 21 print(t1.result()) 22 print(t2.result())
而後還有一個判斷任務是否結束的問題,能夠用as_completed這個方法來實現(用以前要導入= =)
for future in as_completed(all_task): data = future.result()
大概這樣用
還有一個map函數,好比給同一個任務分配不一樣的參數丟進線程池執行
args = ['hello', 'world'] for data in pool.map(task, args): print(data)
這樣用呢省去了submit的步驟,而後有一個就是最後的輸出順序是按照參數的順序來的,而不是執行完成的順序。