协程(coroutine)

协程是什么

协程是一种轻量级的异步编程方式,允许用户编写看似同步实则异步的代码。

协程的本质

协程的本质是一种语法糖,他的出现是用来解决异步问题,但是本身却并不提供异步的能力。

协程是编译器级别的,切换有程序控制,而线程是系统级别的,线程的切换由操作系统控制。

协程的优点

1.轻量级,占用资源更少。

2.避免”回调地狱“

3.挂起不影响线程的其他任务

CoroutineScope和Job

CoroutineScope 协程的的作用范围,每个CoroutineScope都有一个主job,之后所有的launch调用都是创建一个子job。

每个子job都有自己的状态,isCompleted(),isActive(),isCanceled()等,还有一些基础操作,如start(),join(),cancel()等。

子job异常会导致自己结束,不会影响父job,但是父job一场,所有的子job都会停止运行。

launch方法

launch方法有个三个参数,CoroutineContext,CoroutineStart,代码块。

CoroutineContext的本质是一个自定义了获取(get),折叠(fold),组合(plus)等的Element集合。

CoroutineStart标识是否立即执行还是延迟启动。

suspend,delay和runBlocking

delay()函数是协程提供的非阻塞方法,suspend关键字修饰,suspend是协程的内置关键字。

suspend关键字修饰的方法会挂起协程,但是不会影响当前线程继续执行其他线程。

Thread.sleep是阻塞线程的,在协程中如果需要阻塞线程使用runBlocking。

一种有用的实现

CoUtils供所有人简易使用

object CoUtils {

/**

    * 对应于kotlin coroutine的[kotlinx.coroutines.Dispatchers]

    */

    enum class Dispatcher {

/** 使用此调度程序可在 Android 主线程上运行协程*/

        MAIN,

        /** 此调度程序经过了专门优化,适合在主线程之外执行磁盘或网络I/O  */

        IO,

        /** 此调度程序经过了专门优化,适合在主线程之外执行占用大量 CPU 资源的工作*/

        DEFAULT

    }

/**

    * 协程Job的代理,提供部分操作的封装

    */

    class JobControllerinternal constructor(private val job: Job) {

fun cancel(reason: String?) {

job.cancel(CancellationException(reason))

}

val isCompleted: Boolean

get() =job.isCompleted

        val isActive: Boolean

get() =job.isActive

        val isCancelled: Boolean

get() =job.isCancelled

    }

/**

    * 创建一个协程任务

    * @param dispatcher 指定调度器

    * @param runnable 任务

    * @return a [JobController]

    */

    fun launch(dispatcher: Dispatcher, runnable: Runnable): JobController? {

val job = CoWr.launch(dispatcher, runnable)

return JobController(job)

}

/**

    * 创建一个协程任务

    * @param dispatcher 指定调度器

    * @param runnable 任务

    * @param delay 延迟,单位ms

    * @return a [JobController]

    */

    fun launch(dispatcher: Dispatcher, runnable: Runnable, delay: Long): JobController? {

val job = CoWr.launch(dispatcher, runnable, delay)

return JobController(job)

}

/**

    * 创建一个协程任务

    * @param dispatcher 指定调度器

    * @param block 任务

    * @param callback 回调

    * @return a [JobController]

    */

    fun async(dispatcher: Dispatcher, block:() ->T, callback: CoWr.Callback?): JobController? {

val job = CoWr.async(dispatcher, block, callback)

return JobController(job)

}

/**

    * 创建一个协程任务

    * @param dispatcher 指定调度器

    * @param block 任务

    * @return a [JobController]

    */

    fun async(dispatcher: Dispatcher, block:() ->T): JobController? {

val job = CoWr.async(dispatcher, block, null)

return JobController(job)

}

}

CoWr包装协程内部的CoroutineScope

object CoWr {

private const val TAG ="CoTrace"

    private const val TIME_MONITOR =10

    private const val ASYNC_TIME_MONITOR =200

    interface Callback {

fun callback(result:T?)

}

private val exceptionHandler: CoroutineExceptionHandler =

CoroutineExceptionHandler { ctx, error->

            onError(ctx, error)

}

    private val ioScope: CoroutineScope =

CoroutineScope(Dispatchers.IO +SupervisorJob() +exceptionHandler + CoroutineName("io"))

private val defaultScope: CoroutineScope =

CoroutineScope(Dispatchers.Default +SupervisorJob() +exceptionHandler + CoroutineName("default"))

private val mainScope: CoroutineScope =

CoroutineScope(Dispatchers.Main +SupervisorJob() +exceptionHandler + CoroutineName("main"))

fun launch(dispatcher: CoUtils.Dispatcher, runnable: java.lang.Runnable): Job {

return launch(dispatcher, runnable, 0)

}

fun launch(dispatcher: CoUtils.Dispatcher, runnable: java.lang.Runnable, delay: Long): Job {

val enqueueTime = SystemClock.elapsedRealtime()

var startExe =0L

        var endTime =0L

        val job = selectScope(dispatcher).launch {

            startExe = SystemClock.elapsedRealtime()

if (delay >0) {

delay(delay)

}

runnable.run()

endTime = SystemClock.elapsedRealtime()

}

        job.invokeOnCompletion{

            // 执行业务runable,使用的调度器名称,进队时间,在队列里等待时间,执行时间,在协程队列里的总时间

            var cost = endTime - startExe

if (cost >TIME_MONITOR) {

Log.i(TAG,"launchDone:" + runnable.javaClass  +"," + dispatcher.name +"," + enqueueTime

+"," +  (startExe - enqueueTime) +"," + (cost)

+"," + (SystemClock.elapsedRealtime() - enqueueTime))

}

}

        return  job

}

fun async(dispatcher: CoUtils.Dispatcher, block:() ->T, callback: Callback?): Job {

val enqueueTime = SystemClock.elapsedRealtime()

var startExe =0L

        var endTime =0L

        var result:T? =null

        val job = selectScope(dispatcher).launch {

            startExe = SystemClock.elapsedRealtime()

async {

                result = block()

callback?.callback(result)

endTime = SystemClock.elapsedRealtime()

}

}

        job.invokeOnCompletion{

            // 执行业务runable,使用的调度器名称,进队时间,在队列里等待时间,执行时间,在协程队列里的总时间

            var cost = endTime - startExe

if (cost >ASYNC_TIME_MONITOR) {

Log.i(TAG,"asyncDone:" + block.javaClass  +"," + dispatcher.name +"," + enqueueTime

+"," +  (startExe - enqueueTime) +"," + (cost)

+"," + (SystemClock.elapsedRealtime() - enqueueTime))

}

}

        return  job

}

private fun selectScope(dispatcher: CoUtils.Dispatcher): CoroutineScope =when (dispatcher) {

CoUtils.Dispatcher.MAIN ->mainScope

        CoUtils.Dispatcher.IO ->ioScope

        CoUtils.Dispatcher.DEFAULT ->defaultScope

    }

private fun onError(context: CoroutineContext, error: Throwable) {

throw error

}

}

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容