前面講generator是顯式的協程的時候缺一個例子,如今補上多線程
def parent_generator(): print('hello') yield from sub_generator() print('world') def sub_generator(): yield 1 gen = parent_generator() gen.send(None) gen.send(None)
這裏能夠看出parent_generator爲了在hello和world之間中斷,必須顯式的用yield from把控制權從本身手裏轉交給調用者。若是parent_generator沒有使用yield,那麼sub_generator裏即便有yield也沒法使得parent_generator的執行權轉交出去。因此從視覺上能夠一步瞭然的指導一個函數中哪些調用是產生了switch的,哪些是確定順序執行的。有一點相似Haskell裏給全部I/O操做加類型標籤的味道。併發
from greenlet import greenlet def parent(): print('hello') sub() print('world') def sub(): greenlet.getcurrent().parent.switch() g = greenlet(parent) g.switch() print('here is switched from the sub generator') g.switch()
這段代碼的輸出是函數
hello here is switched from the sub generator world
改用greenlet以後,協程之間的跳轉就變得很是隨意了。好比sub裏能夠直接把執行權交給main,而parent徹底不知情。從視覺上來看parent的實現裏徹底不能知道在sub內部發生了switch。
雖然不能和多線程相比,可是效果是相似的。對於多線程的代碼,是任何一行代碼均可能與其餘線程並行。相似greenlet的隱式的協程,雖然不是每一行代碼均可能產生switch。雖然產生switch的地方其實和用yield寫是同樣多,並且也是同樣固定的。可是由於缺乏強制的yield,使得在不閱讀被調用函數內部的實現的前提下,沒法提早知道這個調用是否會產生執行權的遷移。加上協程之間有共享狀態的話,必定程度上會產生相似多線程的併發讀寫狀態的bug。線程