【generator101】 - 對比generator和greenlet

前面講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。線程

相關文章
相關標籤/搜索