Kotlin 协程(1)
来源:互联网 发布:淘宝授权书怎么弄买家 编辑:程序博客网 时间:2024/06/06 03:18
第一个协程程序
fun main(args: Array<String>) { launch { // 启动新的协程 delay(1000L) // 非堵塞延迟一秒 println("World!") // 1秒后答应 } println("Hello,") // 打印Hello, Thread.sleep(2000L) // 阻塞主线程2秒,保持JVM存货}
launch和synchronized一样,算是个语法层面的糖果,实现如下
public fun launch( context: CoroutineContext = DefaultDispatcher, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> Unit): Job { val newContext = newCoroutineContext(context) val coroutine = if (start.isLazy) LazyStandaloneCoroutine(newContext, block) else StandaloneCoroutine(newContext, active = true) coroutine.initParentJob(context[Job]) start(block, coroutine, coroutine) return coroutine}
这个函数的文档描述如下
在不阻塞当前线程的情况下,启动一个线程,并返回一个引用当前协程的对象Job。如果Job对象isCancelled为true,表示协程已经取消。context可以显性赋值,具体可以看CoroutineDispatcher。在父协程的作用域内的context可能会被重用,在这种情况下,子协程的Job对象属于父协程。context的默认值是DefaultDispatcher.默认情况下,协程会马上被执行,CoroutineStart的其他选项是CoroutineStart.LAZY,表示协程只会被创建,而需要调用start函数才会开始工作,CoroutineStart有个invoke方法,所以才能被调用
//CoroutineStart.invoke() public operator fun <T> invoke(block: suspend () -> T, completion: Continuation<T>) = when (this) { CoroutineStart.DEFAULT -> block.startCoroutineCancellable(completion) CoroutineStart.ATOMIC -> block.startCoroutine(completion) CoroutineStart.UNDISPATCHED -> block.startCoroutineUndispatched(completion) CoroutineStart.LAZY -> Unit // will start lazily }
用协程代替主线程
fun main(args: Array<String>) = runBlocking<Unit> { // 启动主协程 launch { // 启动新协程 delay(1000L) println("World!") } println("Hello,") delay(2000L) //延迟主协程2秒,保持JVM存货,非阻塞的}
等待任务完成
fun main(args: Array<String>) = runBlocking<Unit> { val job = launch { println("World!") } println("Hello,") job.join() // 等待子协程completes}
将任务抽象为函数
在协程内执行的函数要有个suspend声明
fun main(args: Array<String>) = runBlocking<Unit> { val job = launch { doWorld() } println("Hello,") job.join()}suspend fun doWorld() { println("World!")}
比较协程和线程
fun main(args: Array<String>) = runBlocking<Unit> { val t0 = System.currentTimeMillis() val jobs = List(100_000) { // launch a lot of coroutines and list their jobs launch { delay(1000L) } } jobs.forEach { it.join() } // wait for all jobs to complete val t1 = System.currentTimeMillis() println(t1-t0) //1.3秒}//使用Thead://Exception in thread "main"//java.lang.OutOfMemoryError: unable to create new native threadfun main(args: Array<String>){ runThread()}fun runThread(){ val t0 = System.currentTimeMillis() val jobs = List(100_000){ val t = Thread{ Thread.sleep(1000) print(".") } t.start() t } jobs.forEach{it.join()} val t1 = System.currentTimeMillis() println(t1-t0)}//将线程数量减小10倍,结果都还是3.6秒,可见协程的效率//原因是线程是系统资源,申请分配和销毁代价等很高。
协程就像守护线程
fun main(args: Array<String>) = runBlocking<Unit> { launch { repeat(1000) { i -> println("I'm sleeping $i ...") delay(500L) } } delay(1300L) // just quit after delay}//I'm sleeping 0 ...//I'm sleeping 1 ...//I'm sleeping 2 ...
取消协程
协程在delay的时候可以被取消
fun main(args: Array<String>) = runBlocking<Unit> { val job = launch { repeat(1000) { i -> println("I'm sleeping $i ...") delay(500L) } } delay(1300L) println("main: I'm tired of waiting!") job.cancel() // 取消任务 job.join() //等待任务完成 println("main: Now I can quit.")}/*I'm sleeping 0 ...I'm sleeping 1 ...I'm sleeping 2 ...main: I'm tired of waiting!main: Now I can quit.*/
协作取消
在CPU运算时,取消操作是没有用的,和线程很像
fun main(args: Array<String>) = runBlocking<Unit> { val startTime = System.currentTimeMillis() val job = launch { var nextPrintTime = startTime var i = 0 while (i < 5) { // computation loop, just wastes CPU // print a message twice a second if (System.currentTimeMillis() >= nextPrintTime) { println("I'm sleeping ${i++} ...") nextPrintTime += 500L } } } delay(1300L) // delay a bit println("main: I'm tired of waiting!") job.cancelAndJoin() // cancels the job and waits for its completion println("main: Now I can quit.")}
使用isActive标志位
fun main(args: Array<String>) = runBlocking<Unit> { val startTime = System.currentTimeMillis() val job = launch { var nextPrintTime = startTime var i = 0 while (isActive) { // cancellable computation loop // print a message twice a second if (System.currentTimeMillis() >= nextPrintTime) { println("I'm sleeping ${i++} ...") nextPrintTime += 500L } } } delay(1300L) // delay a bit println("main: I'm tired of waiting!") job.cancelAndJoin() // cancels the job and waits for its completion println("main: Now I can quit.")}
async函数
async和launch的区别在于,前者是Callable,后者是Runable,你应该懂的
// The result type of asyncSomethingUsefulOne is Deferred<Int>fun asyncSomethingUsefulOne() = async { doSomethingUsefulOne()}// The result type of asyncSomethingUsefulTwo is Deferred<Int>fun asyncSomethingUsefulTwo() = async { doSomethingUsefulTwo()}suspend fun doSomethingUsefulOne(): Int { delay(1000L) // pretend we are doing something useful here return 13}suspend fun doSomethingUsefulTwo(): Int { delay(1000L) // pretend we are doing something useful here, too return 29}// note, that we don't have `runBlocking` to the right of `main` in this examplefun main(args: Array<String>) { val time = measureTimeMillis { // we can initiate async actions outside of a coroutine val one = asyncSomethingUsefulOne() val two = asyncSomethingUsefulTwo() // but waiting for a result must involve either suspending or blocking. // here we use `runBlocking { ... }` to block the main thread while waiting for the result runBlocking { println("The answer is ${one.await() + two.await()}") } } println("Completed in $time ms")}
CoroutineContext
fun main(args: Array<String>) = runBlocking<Unit> { val jobs = arrayListOf<Job>() jobs += launch(Unconfined) { // not confined -- will work with main thread println(" 'Unconfined': I'm working in thread ${Thread.currentThread().name}") } jobs += launch(coroutineContext) { // context of the parent, runBlocking coroutine println("'coroutineContext': I'm working in thread ${Thread.currentThread().name}") } jobs += launch(CommonPool) { // will get dispatched to ForkJoinPool.commonPool (or equivalent) println(" 'CommonPool': I'm working in thread ${Thread.currentThread().name}") } jobs += launch(newSingleThreadContext("MyOwnThread")) { // will get its own new thread println(" 'newSTC': I'm working in thread ${Thread.currentThread().name}") } jobs.forEach { it.join() }}/* 'Unconfined': I'm working in thread main 'CommonPool': I'm working in thread ForkJoinPool.commonPool-worker-1 'newSTC': I'm working in thread MyOwnThread'coroutineContext': I'm working in thread main*/
无约束和有约束的调度器
无约束的(Unconfine)的协程调度器一开始会在调用线程中工作,直到第一次暂停点,在暂停点之后,它会由别的线程接管(?我不确定)无约束的调度器适合于协程不消耗CPU,也不会更新共享数据时使用(因为共享数据最好只由一个专门的线程来控制即,如UI线程)
#
fun main(args: Array<String>) = runBlocking<Unit> { val jobs = arrayListOf<Job>() jobs += launch(Unconfined) { // not confined -- will work with main thread println(" 'Unconfined': I'm working in thread ${Thread.currentThread().name}") delay(500) println(" 'Unconfined': After delay in thread ${Thread.currentThread().name}") } jobs += launch(coroutineContext) { // context of the parent, runBlocking coroutine println("'coroutineContext': I'm working in thread ${Thread.currentThread().name}") delay(1000) println("'coroutineContext': After delay in thread ${Thread.currentThread().name}") } jobs.forEach { it.join() }}/* 'Unconfined': I'm working in thread main'coroutineContext': I'm working in thread main 'Unconfined': After delay in thread kotlinx.coroutines.DefaultExecutor'coroutineContext': After delay in thread main*/
线程间切换
fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")fun main(args: Array<String>) { newSingleThreadContext("Ctx1").use { ctx1 -> newSingleThreadContext("Ctx2").use { ctx2 -> runBlocking(ctx1) { log("Started in ctx1") run(ctx2) { log("Working in ctx2") } log("Back to ctx1") } } }}/*[Ctx1 @coroutine#1] Started in ctx1[Ctx2 @coroutine#1] Working in ctx2[Ctx1 @coroutine#1] Back to ctx1*/
上下文中的Job
这里还真没看懂
fun main(args: Array<String>) = runBlocking<Unit> { println("My job is ${coroutineContext[Job]}")}//My job is "coroutine#1":BlockingCoroutine{Active}@6d311334
协程的子协程
fun main(args: Array<String>) = runBlocking<Unit> { // launch a coroutine to process some kind of incoming request val request = launch { //这个独立的子协程会继续工作,独立于父协程 val job1 = launch { println("job1: I have my own context and execute independently!") delay(1000) println("job1: I am not affected by cancellation of the request") } //子协程继承父协程的上下文,则会随着父协程的取消而取消 val job2 = launch(coroutineContext) { println("job2: I am a child of the request coroutine") delay(1000) println("job2: I will not execute this line if my parent request is cancelled") } // 父协程等待子协程完成任务 job1.join() job2.join() } delay(500) request.cancel() // 取消父协程 delay(1000) println("main: Who has survived request cancellation?")}
合并上下文
合并上下文后的原上下文的协程会被取消
fun main(args: Array<String>) = runBlocking<Unit> { val request = launch(coroutineContext) { // use the context of `runBlocking` // spawns CPU-intensive child job in CommonPool !!! val job = launch(coroutineContext + CommonPool) { println("job: I am a child of the request coroutine, but with a different dispatcher") delay(1000) println("job: I will not execute this line if my parent request is cancelled") } job.join() // request completes when its sub-job completes } delay(500) request.cancel() // cancel processing of the request delay(1000) // delay a second to see what happens println("main: Who has survived request cancellation?")}/*job: I am a child of the request coroutine, but with a different dispatchermain: Who has survived request cancellation?*/
父协程会等待子协程
fun main(args: Array<String>) = runBlocking<Unit> { // launch a coroutine to process some kind of incoming request val request = launch { repeat(3) { i -> // launch a few children jobs launch(coroutineContext) { delay((i + 1) * 200L) // variable delay 200ms, 400ms, 600ms println("Coroutine $i is done") } } println("request: I'm done and I don't explicitly join my children that are still active") } request.join() // wait for completion of the request, including all its children println("Now processing of the request is complete")}/*request: I'm done and I don't explicitly join my children that are still activeCoroutine 0 is doneCoroutine 1 is doneCoroutine 2 is doneNow processing of the request is complete*/
给协程命名:CoroutineName
fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")fun main(args: Array<String>) = runBlocking(CoroutineName("main")) { log("Started main coroutine") // run two background value computations val v1 = async(CoroutineName("v1coroutine")) { delay(500) log("Computing v1") 252 } val v2 = async(CoroutineName("v2coroutine")) { delay(1000) log("Computing v2") 6 } log("The answer for v1 / v2 = ${v1.await() / v2.await()}")}/*[main @main#1] Started main coroutine[ForkJoinPool.commonPool-worker-1 @v1coroutine#2] Computing v1[ForkJoinPool.commonPool-worker-2 @v2coroutine#3] Computing v2[main @main#1] The answer for v1 / v2 = 42*/
使用显性的Job来管理子协程
fun main(args: Array<String>) = runBlocking<Unit> { val job = Job() // create a job object to manage our lifecycle // now launch ten coroutines for a demo, each working for a different time val coroutines = List(10) { i -> // they are all children of our job object launch(coroutineContext + job) { // we use the context of main runBlocking thread, but with our own job object delay((i + 1) * 200L) // variable delay 200ms, 400ms, ... etc println("Coroutine $i is done") } } println("Launched ${coroutines.size} coroutines") delay(500L) // delay for half a second println("Cancelling the job!") job.cancelAndJoin() // cancel all our coroutines and wait for all of them to complete}/*Launched 10 coroutinesCoroutine 0 is doneCoroutine 1 is doneCancelling the job!*/
阅读全文
0 0
- Kotlin 协程(1)
- Kotlin协程
- kotlin协程
- Kotlin(1)
- Kotlin入门(1)搭建Kotlin开发环境
- Kotlin学习(1):Kotlin简介
- Kotlin基础教程-协程
- Kotlin协程(2)
- 1 Introduction To Kotlin
- kotlin(1)-HelloWorld
- Kotlin学习(1)
- Kotlin中的关键字(1)
- Kotlin汇总1
- kotlin深入1
- Kotlin基础 1
- Kotlin实战 1
- kotlin学习笔记1
- 1-35kotlin
- 如何利用抓包工具Fiddler抓取手机的包?
- 20_IO流
- 从零开始学电脑 1.3
- 多因子模型之组合构建与优化器(上)
- SparkCore程序可能遇到的异常
- Kotlin 协程(1)
- UIApplicationDelegate 里面最常用的几个函数执行顺序小结
- A Summary of 'Emotion in Reinforcement Learning Agents and Robots: A Survey'
- 21_IO流
- java.lang.ClassNotFoundException: org.apache.xbean.spring.context.v2.XBeanNamespaceHandler
- win7与ubuntu14.04双系统下修改默认启动项
- LaTex(PART VIII)文档类和页面布局相关
- 22_IO流
- Java Thread