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!*/
原创粉丝点击