突然簡書就不支持使用markdown語法自己編輯了,而是和word一樣自己選擇要樣式化的文本,實在是令人很不習慣,準備搭建一個Github主頁算了。
使用協(xié)程的一個典型例子是生產(chǎn)者消費者模型。我感慨道,果然什么語言不重要啊,思想都是一致的,想起LabVIEW當時用這個生產(chǎn)者消費者用的順風順水,因為實在是太好用了,當時編寫的每一個系統(tǒng)都嘗試使用生產(chǎn)者消費者,特別是與用戶交互的界面中,用這個模型簡直極大的優(yōu)化用戶的點擊體驗。當時是使用隊列來實現(xiàn)狀態(tài)的轉移,從生產(chǎn)者轉移到消費者循環(huán)里面進行處理。
今天使用Python來實現(xiàn)一個簡單的生產(chǎn)者消費者模型,主要是為了學習協(xié)程這個東西,因為Python其實是不支持多線程并行運算,它的多線程其實也是串行的。協(xié)程是協(xié)作式調(diào)度,大概就是一種可控制的回調(diào),使用yield來實現(xiàn)。
主要思想就是用yield來暫停當前的程序或者循環(huán),然后轉而執(zhí)行另外一個,再在恰當?shù)臅r候回來執(zhí)行。其實本質(zhì)上和LabVIEW的生產(chǎn)者消費者有所不同,因為LabVIEW中是支持多線程的,所以生產(chǎn)者消費者是處于兩個線程來執(zhí)行的兩個循環(huán),因此才使用了隊列數(shù)據(jù)結構來轉移狀態(tài)。
下面是一個簡單的生產(chǎn)者消費者模型:
def consumer():
n = 0
print("consumer init")
while True:
#在這里將函數(shù)暫停掉,直到另外地方對函數(shù)進行迭代,如producer函數(shù)
n = yield n
if not n:
return
n -= 1
print("consume 1, remain %d" %n)
def producer(c):
n = 0
next(c)
while n < 6:
n += 2
print("produce 2, total %d " %n)
#send給generator的value會成為當前yield的結果 并且send的返回結果是下一個yield的結果
#也就是這里send了2,那邊n的值就是2,然后減一,然后直到再運行到y(tǒng)ield時候,這里返回的是1
n = c.send(n)
print("remain %d"%n)
c.close()
c = consumer()
producer(c)```
producer和consumer協(xié)同合作,在一個線程中運行,不需要鎖,所以就不會出現(xiàn)死鎖。
另外使用協(xié)程也可以來定義一個可以訪問其他環(huán)境的回調(diào)函數(shù)
首先定義一個回調(diào)函數(shù)
def apply_async(func,args,,callback):
#callback是一個強制關鍵字參數(shù)
result = func(*args)
callback(result)
def add(x,y):
return x + y
這個回調(diào)函數(shù)其實就類似于一個消費者
def make_handler():
sequence = 0
while True:
#產(chǎn)生中斷
result = yield
sequence += 1
print("[{}] Got : {}".format(sequence,result))
handler = make_handler()
啟動生成器
next(handler)
apply_async(add,(2,3),callback=handler.send)
apply_async(add,("hello ","world"),callback=handler.send)```