在前面幾個博客中咱們一一對應解決了消費者消費的速度跟不上生產者,浪費咱們大量的時間去等待的問題,在這裏,針對業務邏輯比較耗時間的問題,咱們還有除了多進程以外更優的解決方式,那就是協程和異步協程。在引入這個概念以前咱們先看 看這個圖: html
從這個圖片咱們能夠看出來,假如來了9個任務,即便咱們開了多進程,在業務的執行過程當中咱們依舊是同步操做,因此執行完這一波任務咱們一共須要9s,雖然比單進程快了3倍,可是在機器條件能夠(確定能夠)的狀況下,咱們如何更加合理的利用給咱們的資源呢?因而異步協程的優點就來了:python
根據這張圖咱們能夠看出來,在任務1執行完業務邏輯1的時候,任務2就能夠開始執行,這樣當任務2執行完業務邏輯1的時候,任務3就開始執行了,這樣咱們3個進程,總共耗時只須要5s,比上面同步的方式快了足足4s,省去了等待的時間,讓模塊之間銜接和調用更加充分。編程
在python中,咱們先介紹一下2.0的協程:gevent的使用,在python3.4以後添加了syncoio的使用,這篇博客咱們就專門針對業務邏輯部分進行深度的優化:網絡
gevent是第三方庫,經過greenlet實現協程,其基本思想是:異步
當一個greenlet遇到IO操做時,好比訪問網絡,就自動切換到其餘的greenlet,等到IO操做完成,再在適當的時候切換回來繼續執行。因爲IO操做很是耗時,常常使程序處於等待狀態,有了gevent爲咱們自動切換協程,就保證總有greenlet在運行,而不是等待IO(引用)。async
好比下面代碼:oop
from gevent import monkey monkey.patch_all() import gevent import time # TODO 此處是業務邏輯操做 def logicDel(data): time.sleep(2) print('im running',data) if __name__ == '__main__': # 在這裏咱們聲明幾個任務,把任務放到一個list中去作分配調度 tasks=[gevent.spawn(logicDel,data) for data in range(9)] gevent.joinall(tasks)
咱們能夠看到咱們在一個tasks裏面9個任務,每一個任務執行都要sleep2秒,若是是阻塞式運行就須要18s,可是咱們加入了協程,全部的任務完成只須要2s,其中原理和上圖(異步加載圖)同樣,這裏就不贅述了。優化
然而有時候咱們代碼業務邏輯中一個業務執行不僅有一個任務,其中每一個任務之間還有調度依賴的關係,這時候咱們的gevent就顯得有點力不從心了,這裏就引進了python3.4以後的一個自帶的包asyncio——異步協程。spa
asyncio的編程模型就是一個消息循環。咱們從asyncio模塊中直接獲取一個EventLoop
的引用,而後把須要執行的協程扔到EventLoop
中執行,就實現了異步IO。用asyncio
實現Hello world
代碼以下:code
import threading import asyncio @asyncio.coroutine def hello(): print('Hello world11111111 (%s)' % threading.currentThread()) yield from asyncio.sleep(1) print('Hello again22222222 (%s)' % threading.currentThread()) loop = asyncio.get_event_loop() tasks = [hello(), hello()] loop.run_until_complete(asyncio.wait(tasks)) loop.close()
其中每一個tasks都是非阻塞式的,固然這個仍是沒有解決一個業務有多個任務且每一個任務之間存在依賴關係應當怎麼解決的問題,由於咱們尚未引用async await:
import asyncio import time # Borrowed from http://curio.readthedocs.org/en/latest/tutorial.html. # @asyncio.coroutine async def myslep(n): print(n) time.sleep(10) asyncio.sleep(5) async def countdown(number, n): while n > 0: print('T-minus', n, '({})'.format(number)) # await myslep(n) tasks2=[] await asyncio.ensure_future(myslep(n)) # time.sleep(2) n -= 1 loop = asyncio.get_event_loop() tasks = [ asyncio.ensure_future(countdown("A", 2)), asyncio.ensure_future(countdown("B", 3)), asyncio.ensure_future(countdown("C", 3)), ] loop.run_until_complete(asyncio.wait(tasks)) loop.close()