一、协程的分类:
1、按调用栈分:
有栈协程:每隔协程会分配单独的类似线程的调用栈,比如Lua Coroutine;
无栈协程:不会分配单独的调用栈,挂起点的状态通过闭包或者对象来保存,没办法嵌套函数,实现挂起,比如Python Generator。挂起和恢复没有函数的嵌套是无盏协程的非常典型的特征,否则即为有盏协程。
有栈协程涉及到分配独立的内存等硬件资源,这是额外的资源开销,因此有栈协程的使用受到一定限制,没有无栈协程受欢迎。
Kotlin、JavaScript、C#这些语言的协程都是属于无栈协程。
2、按调用关系分:
对称协程:调度权可以转移给任意协程,协程之间是对等关系——在并发里面用的很多
非对称协程:调度权只能转移给调用自己的协程,协程存在“父子”关系——常见场景就是异步。在Android里面最常见的就是Main线程调用网络请求API,子线程请求数据,然后回调Main线程更新UI;Python里面的yield()挂起函数只能将调度权转移给对应的resume()函数。
在kotlin的开发里面,我们实现的绝大部分都是非对称的协程。
当下,协程的一个相当主流的实现:async/await
支持他们的语言很多,包括C#5.0+、JavaScript ES6+、Kotlin 1.3+、Rust 1.39.0+、Python3.5+等等。
下一节我们进入kotlin的协程,现在我们先来看看Async在JavaScript里面的同步实现:
function getUser(name){
return axios.get('https://api.github.com/users/${name}')
}
async function main(){
const user = await getUser("haoyue");
console.log(user)
}
再来看看异步实现:
async function main(){
const userPromise = getUser("haoyue");
userPromise.then(user => {
console.log(user);
}).catch(e => {
console.error(e)
});
}
“async/await”是可以多层嵌套的,但是嵌套的话,则需是“async functio…”的形式;另外它是一种无栈的非对称式的协程实现。
在kotlin里面,则有些不一样,kotlin里面没有“async/await”这两个关键字,取而代之的是“Suspend”关键字。
而且kotlin协程API可以实现上面的所有功能特性。