【Kotlin】协程(四)

4.1 协程上下文调度器

通过前面的学习,我们了解到协程的基本使用,我们都知道最简单的方式启动协程就是通过GlobalScope.launch(){}方式启动协程,那么我们看看这个方法到底做了什么吧

我们先看 GlobalScope 的实现:

//GlobalScope
@DelicateCoroutinesApi
public object GlobalScope : CoroutineScope {
    /**
     * Returns [EmptyCoroutineContext].
     */
    override val coroutineContext: CoroutineContext
        get() = EmptyCoroutineContext
}

// CoroutineScope
public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext,
    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.start(start, coroutine, block)
    return coroutine
}

我们通过源码发现,GlobalScope 是继承自CoroutineScope,而CoroutineScope的 launch 函数,就是协程的入口,主要包含的参数有三个,分别是 CoroutineContext,CoroutineStart,以及一个挂起函数,返回值是一个 Job。这里我们先从 CoroutineContext这个参数讲起。

CoroutineContext是一个接口,内部有一个 Element 接口继承CoroutineContext,还有一个 Key 的接口,在CoroutineContext注释里,是这样描述CoroutineContext的,意思是CoroutineContext是一组 Element 的实例索引,每一个索引都有一个唯一的 Key。

在这里插入图片描述

我们看 Element 的实现类起始有很多,今天我们主要讲协程的任务分发调度器 --Dispatchers:

在这里插入图片描述

通过上面图示,我们可以看到 Kotlin 提供了四中 Dispatcher,分别是

  • Default :顾名思义,Default 也就是默认值,当不设置任何调度器的时候,就默认为这个调度器
  • Main :主调度器,也就是在主线程中使用此调度器,
  • Unconfined :不受限制的调度器(比较复杂,后续说明)
  • IO : 用于IO 操作的协程调度器

我们简单试一下这几个调度器的使用

import kotlinx.coroutines.*

fun main() = runBlocking<Unit> {
    launch { //不设置调度器
        println("runBlocking      : I'm working in thread ${Thread.currentThread().name}")
    }
    launch(Dispatchers.Unconfined) { // 不受限的——将工作在主线程中
        println("Unconfined            : I'm working in thread ${Thread.currentThread().name}")
    }
    launch(Dispatchers.Default) { // 将会获取默认调度器
        println("Default               : I'm working in thread ${Thread.currentThread().name}")
    }
    launch (Dispatchers.IO){ // 将会获取IO调度器
        println("IO               : I'm working in thread ${Thread.currentThread().name}")
    }
}

输出的结果为:

在这里插入图片描述

这里我们可以看到不设置调度器的时候,并没有使用DefaultDispatcher,而是使用了Main 调度器,这里是因为,子协程会默认使用启动该协程的CoroutineScope 中的调度器。 runBlocking 使用的是 Main。可能还会有一个疑问,为什么 IO 调度器不是 IO 呢,这是因为 IO 调度器起始也是通过默认调度器里的线程池实现的,这个我们后续讲解原理。

注意

  • 当协程在GlobalScope中启动时,使用的是由 Dispatchers.Default代表的默认调度器。 默认调度器使用共享的后台线程池。 所以 launch(Dispatchers.Default) { …… }GlobalScope.launch { …… } 使用相同的调度器。

  • 当我们不想使用 kotlin默认的调度器,是可以自己创建线程调度器的,使用方法为newSingleThreadContext(name: kotlin.String)以及newFixedThreadPoolContext(nThreads: kotlin.Int, name: kotlin.String),这里有点像 Java 通过 Executors 创建线程池。(在这里为协程创建线程/线程池是非常消耗资源的,所以在不是用的时候需要及时释放)

    launch (newSingleThreadContext("single")){
        println("single               : I'm working in thread ${Thread.currentThread().name}")
    }
    launch( newFixedThreadPoolContext(2,"multi")) {
        println("multi               : I'm working in thread ${Thread.currentThread().name}")
    }
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

0neXiao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值