协程:相互协作的程序
⼀些 API 启动⻓时间运⾏的操作(例如⽹络 IO、⽂件 IO、CPU 或 GPU 密集型任务等),并要求调⽤者阻塞直到它们完成。协程提供了⼀种避免阻塞线程并用更廉价、更可控的操作替代线程阻塞的⽅法:协程挂起
协程通过将复杂性放⼊库来简化异步编程。程序的逻辑可以在协程中顺序地表达,而底层库会为我们解决其异步性。该库可以将用户代码的相关部分包装为回调、订阅相关事件、在不同线程(甚至不同机器!)上调度执行,而代码则保持如同顺序执行⼀样简单
一、准备工作
由于协程目前还没有纳入kotlin标准库,所以要使用协程,需先进行以下配置
kotlin { experimental { coroutines 'enable' } } dependencies { implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.20' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:0.20'}
二、协程的优点
将异步,回调,订阅等代码,简化成顺序执行代码一样
普通回调方式
var a返回值 = A任务() B任务(a返回值){ b返回值 -> //回调方法 C任务(b返回值){ c返回值 -> //回调方法 D任务(c返回值) } }
loadDataFromNet { println(it) }private fun loadDataFromNet(callback: (String) -> Unit){ Thread{ Thread.sleep(3000) callback("这是网络请求后的结果") } }
使用协程
协程{ D任务( C任务( B任务( A任务() ) ) ) }
async { val message = loadDataFromNet() println(message) }private suspend fun loadDataFromNet() : String{ delay(3000) return "这是网络请求后的结果"}
轻量级线程
val jobs = List(100_000) { launch { delay(1000) print("*") } } launch { jobs.forEach { it.join() } }
开启了10w个协程,会正常打印出来。如果换成Thread会抛出 out of memory
三、创建一个协程
launch 与 async
launch方法返回一个Job类型,并不会返回值;sync有返回值
//launch 创建的 是Jobval job = launch { delay(1000) println("launch") }//async 创建的 是Deferred, Deferred是Job的一个子类val deferred = async { delay(1000) println("async") return 1 //async 才能有return}
runBlocking { }也是一个协程,不过一般不这样使用
指定线程
launch (UI){ } //UI 线程launch (CommonPool){ } //普通线程async(UI) { }async(CommonPool){ }
协程的行为控制
delay(millis:Long):协程挂起Deffered.join():类似Thread.join Deffered.cancel():协程取消,可携带一个 Exception 实例作为参数,以在协程取消时抛出该异常,可以通过返回值判断协程是否取消成功Deffered.await():等待直接获取协程返回值
四、挂起函数 suspend
被suspend 修饰的函数为挂起函数,挂起函数 只能在协程中调用
private suspend fun loadDataFromNet() : String{ delay(3000) return "这是网络请求后的结果"}
五、其他
yield
val fibonacci = buildSequence { var cur = 1 var next = 1 while (true) { yield(next) val tmp = cur + next cur = next next = tmp } } println(fibonacci.take(20).toList())
打印结果
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]
Channels(通道)
之前说的都是一个一个协程独立工作,但是实际使用中协程经常会相互协作,比如生产者消费者。这其中很重要的一个东西就是协程之间的数据通信。Channel就是协程数据通信的一个重要手段。
fun channelTest() = runBlocking<Unit> { val channel = Channel<Int>() launch { // this might be heavy CPU-consuming computation or async logic, we'll just send five squares Log.d("sss","start send value") for (x in 1..5) { Log.d("sss","send value ${x*x}") channel.send(x * x) } Log.d("sss","end send value") } // here we print five received integers: repeat(5) { Log.d("sss",channel.receive().toString()) } Log.d("sss","Done!") }// D/sss: start send value// D/sss: send value 1// D/sss: send value 4// D/sss: 1// D/sss: send value 9// D/sss: 4// D/sss: 9// D/sss: send value 16// D/sss: send value 25// D/sss: 16// D/sss: 25// D/sss: Done!// D/sss: end send value
作者:Teprinciple
链接:https://www.jianshu.com/p/1d7fd1431487