結(jié)論:promise, async, await 是不完全的抽象,coroutine更適合異步開(kāi)發(fā),解放心智負(fù)擔(dān)。
近來(lái),nodejs, python的發(fā)展,有些看不大懂。
nodejs由于其異步io的純粹,在web服務(wù)器上的超高性能,獲得了極大的關(guān)注和發(fā)展。
其關(guān)鍵特性,異步處理這塊上,是這樣發(fā)展的
callback有回調(diào)地獄的問(wèn)題
promise把回調(diào)樹(shù)平展開(kāi)來(lái),代碼更好閱讀
generator真以同步寫(xiě)異步
async,await以同步的方式來(lái)書(shū)寫(xiě)異步的代碼
python由于GIL的存在,在多線程處理上是沒(méi)有未來(lái)的。
所以python的web服務(wù)器基本上走的都是多進(jìn)程的路子。
多線程也好,多進(jìn)程也好,都是上個(gè)時(shí)代的處理方式,解決c10k都?jí)騿?br>
梳理下python在web服務(wù)器上的發(fā)展:
多進(jìn)程 例如
uWSGI服務(wù)器。 性能其實(shí)也夠用了
回調(diào) 例如tornado沒(méi)有很詳細(xì)的了解, 知道性能很高,有回調(diào)地獄的問(wèn)題
greenlet技術(shù) 不了解有什么常用的服務(wù)器或者web框架出來(lái)
asyncio
python3.5也引入了async,await
總結(jié)一下
總之,io上,只有兩種模型:
- 同步io
- 異步io
想擁有更高的性能,只有異步io可以解決。然后如下幾個(gè)共識(shí):
- 回調(diào)嵌套回調(diào),真心不適合人寫(xiě)的,太亂
- promise只是展平了,看起來(lái)好點(diǎn)了,但是流程的流轉(zhuǎn),與異常的結(jié)合還是不好
- async, await只是promise的再包裝,本質(zhì)沒(méi)變。babel對(duì)async,await的支持就是通過(guò)轉(zhuǎn)化成promise來(lái)實(shí)現(xiàn)的
coroutine
之前看過(guò)一種說(shuō)法,
coroutine保留了lisp的續(xù)延特性的精華
什么是coroutine
coroutine 是由用戶調(diào)度的調(diào)用棧,即輕量線程
為什么說(shuō)coroutine更適合異步開(kāi)發(fā),
舉個(gè)例子
這是await版
async function selectPizza() {
const pizzaData = await getPizzaData() // async call
const chosenPizza = choosePizza() // sync call
await addPizzaToCart(chosenPizza) // async call
}
async function selectDrink() {
const drinkData = await getDrinkData() // async call
const chosenDrink = chooseDrink() // sync call
await addDrinkToCart(chosenDrink) // async call
}
(async () => {
const pizzaPromise = selectPizza()
const drinkPromise = selectDrink()
await pizzaPromise
await drinkPromise
orderItems() // async call
})()
這是lua的coroutine版
function selectPizza()
local pizzaData = getPizzaData() // async call
local chosenPizza = choosePizza() // sync call
addPizzaToCart(chosenPizza) // async call
end
function selectDrink()
local drinkData = getDrinkData() // async call
local chosenDrink = chooseDrink() // sync call
addDrinkToCart(chosenDrink) // async call
end
(function ()
selectPizza()
selectDrink()
orderItems() // async call
end)()
可以看到,coroutine可以做到跟同步多線程一樣的寫(xiě)法
再舉個(gè)例子, 異步與map的結(jié)合
這是await版
var arr = [1, 2, 3, 4, 5];
var results = await Promise.all(arr.map(async (item) => {
await callAsynchronousOperation(item);
return item + 1;
}));
這是lua的coroutine版
local arr = {1,2,3,4,5}
local results = arr.map(function (item)
callAsynchronousOperation(item)
return item + 1
end)
注 兩者功能并不完全一樣
await版,寫(xiě)庫(kù)函數(shù)的人,需要關(guān)心庫(kù)函數(shù)是異步的,調(diào)用方也需要關(guān)心
所調(diào)用的函數(shù)是異步的,要用await去等待,并且聲明調(diào)用了await的函數(shù)要用async修飾。
coroutine版可以做到真正的以同步的方式來(lái)寫(xiě)異步的代碼。
同時(shí),coroutine可以真正自然地與try-catch異常處理結(jié)合,而await需要做更多的處理
在人月神話中,就有提到,程序的主要復(fù)雜度是不可減的,
人腦是無(wú)法巨細(xì)無(wú)遺地面對(duì)所有復(fù)雜度的。 所以程序架構(gòu)的本質(zhì)是管理并屏蔽復(fù)雜度
面向?qū)ο蟮娜筇卣鳎?code>封裝、繼承、多態(tài)中,最有用的是
*封裝屏蔽復(fù)雜度
*多態(tài)歸一化處理
基于以上的認(rèn)識(shí),我們知道,coroutine真正的屏蔽了異步帶來(lái)的復(fù)雜度和心智負(fù)擔(dān),這在實(shí)際開(kāi)發(fā)中,幫助是巨大的。
大火的golang,相較于它的競(jìng)爭(zhēng)者,優(yōu)勢(shì)突出,突出在于它的goroutine(特殊的coroutine)
推薦
-
openrestynginx、coroutine、 web服務(wù)器,中間件 -
skynetactor model、coroutine、 游戲服務(wù)器