協程,英文名稱爲 Coroutine,常常被稱爲微線程,纖程,是一種多任務併發的操做手段
PYTHON 中的多任務處理,根據資源消耗狀況能夠選擇多進程併發、多線程併發,同時也可
以在節省系統資源的狀況下選擇協程併發,協程因爲是工做在一個線程中的執行單元,因此
系統資源消耗是最少的python
因爲協程省去了多線程、多進程併發機制下的切換管理和狀態數據管理等,因此操做效率較
高,PYTHON 不一樣的版本中提供了很多關於協程的支持,咱們從最簡單的多任務併發逐步深
入瞭解 PYTHON 中的協程多線程
協程既然是多任務併發,確定是參考了多線程的工做機制,咱們安裝 gevent 模塊完成最基
本的多任務操做協程
pip install gevent
併發
咱們回到最初的多任務併發,要求在程序中一邊唱歌一邊跳舞的功能實現異步
import time from greenlet import greenlet def sing(): # 定義唱歌的函數 while True: print("唱歌》》》") time.sleep(1) # 切換運行協程2 g2.switch() def dance(): while True: print("跳舞》》》》") time.sleep(1) # 切換運行協程1 g1.switch() if __name__ == "__main__": # 建立兩個協程對象 g1 = greenlet(sing) g2 = greenlet(dance) # 切換到協程1工做 g1.switch() print("主進程執行...")
咱們經過事件操做模塊gevent,讓多個任務根據本身的運行狀態進行自動切換async
import gevent import threading def sing(): # 定義唱歌函數 while True: print("唱歌>>>", threading.current_thread().getName()) # 事件休眠,讓出執行時間片 gevent.sleep(1) def dance(): # 定義跳舞函數 while True: print("跳舞>>>", threading.current_thread().getName()) # 事件休眠,讓出時間片 gevent.sleep(3) if __name__ == "__main__": # 常見跳舞、唱歌的協程 s = gevent.spawn(sing) d = gevent.spawn(dance) # 獨佔時間片運行 s.join() d.join()
執行代碼運行程序,能夠看到他們是工做在一個線程中的執行單元函數
Python 中爲了有效的利用內存進行程序的運算操做,提供了一個生成器對象 yield
所謂生成器,就是在程序運行執行到該代碼時才參與運算獲得結果,常常被用做協程操做和
組合數據類型的推導生成
因爲其執行即運算的特性,經過生成器操做也能夠完成協程的處理oop
import time def sing(): while True: time.sleep(1) print("唱歌》》》") yield def dance(): while True: time.sleep(1) print("跳舞>>>") next(s) if __name__ == "__main__": s = sing() d = dance()
生成器對象主要的核心函數就是next(),經過next()方法才能執行運算獲得運算的下一個結果值,因此這裏有效的利用yield完成了一次協程的工做。可是畢竟yield錯作協程的可讀性較差。優化
PYTHON3.4 版本中添加了異步 io 操做模塊 asyncio,對於協程的操做支持就變得比較友好
了,經過異步 io 操做,能夠將多路 io 程序經過協程的方式提高操做效率spa
import asyncio # 添加一個註解,標註這個函數是一個協程函數 @asyncio.coroutine def show_info(name): for i in range(0, 10): print(name, "輸出數據>>>") # 異步執行代碼,模擬耗時2s yield from asyncio.sleep(2) if __name__ == "__main__": # 獲取異步IO時間輪詢對象 loop = asyncio.get_event_loop() # 編譯執行 loop.run_until_complete(asyncio.gather(show_info("tom"), show_info("jerry"))) # 關閉時間 輪詢 loop.close()
前面那個唱歌跳舞的異步IO協程改版線程
import asyncio @asyncio.coroutine def sing(): while True: print("唱歌》》》") yield from asyncio.sleep(2) @asyncio.coroutine def dance(): while True: print("跳舞》》》") yield from asyncio.sleep(2) if __name__ == "__main__": loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.gather(sing(), dance())) loop.close()
PYTHON3.5 又增長了新的操做機制以提升對協程的支持
新增 async 替代了原來的@asyncio.corotine,新增 await 替代了原有的 yield from 步驟,簡
化和優化了原有協程處理流程,這一部分異步操做,在之後的各個須要異步操做的方面都有
着很是普遍的應用。
import asyncio async def sing(): while True: print("唱歌》》》") # 異步操做 await asyncio.sleep(2) async def dance(): while True: print("不如跳舞》》》") await asyncio.sleep(1) if __name__ == "__main__": loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.gather(sing(), dance())) loop.close()