结论:promise, async, await 是不完全的抽象,coroutine更适合异步开发,解放心智负担。
近来,nodejs, python的发展,有些看不大懂。
nodejs由于其异步io的纯粹,在web服务器上的超高性能,获得了极大的关注和发展。
其关键特性,异步处理这块上,是这样发展的
callback
有回调地狱的问题
promise
把回调树平展开来,代码更好阅读
generator
真以同步写异步
async,await
以同步的方式来书写异步的代码
python由于GIL
的存在,在多线程处理上是没有未来的。
所以python的web服务器基本上走的都是多进程的路子。
多线程也好,多进程也好,都是上个时代的处理方式,解决c10k
都够呛
梳理下python在web服务器上的发展:
多进程 例如
uWSGI
服务器。 性能其实也够用了
回调 例如tornado
没有很详细的了解, 知道性能很高,有回调地狱的问题
greenlet
技术 不了解有什么常用的服务器或者web框架出来
asyncio
python3.5也引入了async,await
总结一下
总之,io上,只有两种模型:
- 同步io
- 异步io
想拥有更高的性能,只有异步io可以解决。然后如下几个共识:
- 回调嵌套回调,真心不适合人写的,太乱
- promise只是展平了,看起来好点了,但是流程的流转,与异常的结合还是不好
- async, await只是promise的再包装,本质没变。babel对async,await的支持就是通过转化成promise来实现的
coroutine
之前看过一种说法,
coroutine保留了lisp的续延特性的精华
什么是coroutine
coroutine 是由用户调度的调用栈,即轻量线程
为什么说coroutine更适合异步开发,
举个例子
这是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可以做到跟同步多线程一样的写法
再举个例子, 异步与map的结合
这是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版,写库函数的人,需要关心库函数是异步的,调用方也需要关心
所调用的函数是异步的,要用await去等待,并且声明调用了await的函数要用async修饰。
coroutine版可以做到真正的以同步的方式来写异步的代码。
同时,coroutine可以真正自然地与try-catch异常处理结合,而await需要做更多的处理
在人月神话中,就有提到,程序的主要复杂度是不可减的,
人脑是无法巨细无遗地面对所有复杂度的。 所以程序架构的本质是管理并屏蔽复杂度
面向对象的三大特征,封装
、继承
、多态
中,最有用的是
*封装
屏蔽复杂度
*多态
归一化处理
基于以上的认识,我们知道,coroutine真正的屏蔽了异步带来的复杂度和心智负担,这在实际开发中,帮助是巨大的。
大火的golang,相较于它的竞争者,优势突出,突出在于它的goroutine(特殊的coroutine)
推荐
-
openresty
nginx、coroutine、 web服务器,中间件 -
skynet
actor model、coroutine、 游戏服务器
网友评论