有栈协程&无栈协程
早起很多书籍和文章把协程成为subroutine,subroutine就是函数,从单词构成上也能理解它大概的意思,sub-routine。
而后来的coroutine就是可以中断并恢复执行的subroutine。唯一区别就是它强调了可以中断挂起,并且恢复,对应的操作就是yield/resume,也就是说把协程当做一个特殊的函数函数调用。
把协程当做一个特殊的函数调用,就需要像函数一样去切换,函数本身就有调用栈,协程的切换就是通过上下文,上下文本质上就是寄存器。
Golang中的goroutine,js里的async/await。
这里的 有栈和无栈的意思不是指协程在运行时是否需要栈空间,因为对于大多数语言来说,一个函数调用另一个函数总是存在调用栈的。
而是指协程是否可以在其任意嵌套函数中被挂起。
有栈协程,即能通过运行时 上下文实现 挂起,恢复
无栈协程,不能
显然有栈协程可以,无栈协程不可以。
对称协程&非对称协程
对称在这里的意思就是 协程之间是否有 抽象意义上的对称关系,即,协程之间不存在调用依赖的优先级关系,每个之间都是彼此独立,对称
- 对称协程 Symmetric Coroutine:任何一个协程都是相互独立且平等的,调度权可以在任意协程之间转移。
- 非对称协程 Asymmetric Coroutine:协程出让调度权的目标只能是它的调用者,即协程之间存在调用和被调用关系。
总结
协程的有栈,无栈的本质区别就是 是否可以在 嵌套函数调中被挂起,恢复。
比如用javascript就不能这么写
async function processArray(array) {
// 显然这里 forEach 是个嵌套函数
array.forEach(item => {
// Uncaught SyntaxError:
// await is only valid in async function
const result = await doSomething(item)
...
})
}
但是有栈协程的goroutine就可以这么写:
func processArray(array []int) {
for i := 0; i < len(array); i++ {
ch := make(chan int)
go doSomething(array[i], ch)
result := <- ch
...
}
}
计算机的任何功能上的提升都是要牺牲一定的性能(额外资源),显然有栈协程功能上更强大,但是没有无栈协程性能高。