Kotlin的协程理解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_21700489/article/details/79277225

  
   
1. 协程,微线程,纤程。英文名Coroutine。
2. 协程不是进程也不是线程,它的执行过程更类似于子例程。或者说不带返回值的函数调用。
3. 一个程序中可以包含多个协程,类似于 一个进程可以包含多个线程。

  协程和线程的区别:
  
   多个线程相对独立,有自己的上下文,但他的切换受系统控制
协程也是相对独立,有自己的上下文,但它的切换是由自己控制的,可以由自身决定是否切换到其它的协程中

  函数调用总是一个入口,一次返回,调用顺序是明确的。
协程看上去也是子程序(函数),但在执行过程中,在子程序内部可中断,然后转而执行其他的子程序,在适当的时候再返回来接着执行。

  注意:在一个子程序中中断,去执行其它子程序,不是函数调用,有点类似于CPU的中断。

  协程的特点在于:一个线程执行

  协程的优势:

  1. 极高的执行效率。协程的子程序切换不是线程切换,而是由程序自身控制,因此,协程没有线程切换的开销。
  2. 不需要多线程的锁机制,因为只有一个线程,也不存在 “同时写变量冲突”,在协程中控制共享资源不加锁,只需要判断状态即可。

接下来我们来看一下Kotlin一些关键方法的源码

注意:由于Kotlin的协程还在试验阶段,所以一些代码或者方法以后很可能会有新的变动,这里我使用的版本为:
implementation ‘org.jetbrains.kotlinx:kotlinx-coroutines-core:0.22.1’
implementation “org.jetbrains.kotlinx:kotlinx-coroutines-android:0.22.1”

  1. 首先是launch方法
/**
 * 该方法将会在不阻塞当前线程的情况下启动新的协程程序,并且将会返回一个 [Job] 对象,该对象是对这个协程程序的引用.
 * 当这个返回的结果 [Job]对象 被 [cancelled] 或者 [Job.cancel]时,这个启动的协程会被取消.
 * 
 * 可以显示地为这个新创建的协程指定一个 [context] 上下文对象.
 * 请参阅 "kotlinx.coroutines" 提供的标准上下文实现的 .
 * [CoroutineDispatcher]可使用父协同程序的[context][CoroutineScope.coroutineContext] [scope] [CoroutineScope],
 * 在这种情况下, 该协同程序的返回的[Job] 是其父协同程序 job 的子级。
 * 父作业也可以使用 [parent] 参数显式指定。
 *
 * 如果上下文没有任何调度程序或任何其他[ContinuationInterceptor], 则使用 [DefaultDispatcher]。
 *
 * 默认情况下,协程程序会立即计划执行。
 * 当然,你可以通过指定 `start` 参数选择不马上计划执行。有关详细信息, 请参阅 [CoroutineStart] 
 * 
 * 可选 [start] 参数可以设置为 [CoroutineStart] 以_lazily_的方式启动协同程序 。在这种情况下,
 * 协同程序 [Job] 是在 _new_ 状态下创建的。可以使用 [start][Job.start] 方法手动地启动该函数
 * 并且将在第一次调用 [join][Job.join] 时隐式启动。
 * 
 * 默认情况下, 任何捕获异常会取消父作业(除非明确指定 [CoroutineExceptionHandler]),
 * 这意味着当 "launch" 指定的协程上下文context对象是来自另一个协同程序的上下文context对象时,
 * 任何捕获异常会导致父协同程序的取消。
 *
 * 请参阅 [newCoroutineContext] 以了解对新创建的协同程序可用的调试设施的说明。
 *
 * @param context 协程上下文. 默认值为  [DefaultDispatcher].
 * @param start 协同程序启动选项。默认值为 [CoroutineStart. default]。
 * @param parent 显式指定父作业, 会覆盖 [context] 中的作业 job(如果有的话)。
 * @param block 需要在该协同程序中被执行的代码块
 */
public actual fun launch(
    context: CoroutineContext = DefaultDispatcher,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    parent: Job? = null,
    block: suspend CoroutineScope.() -> Unit
): Job {
    val newContext = newCoroutineContext(context, parent)
    val coroutine = if (start.isLazy)
        LazyStandaloneCoroutine(newContext, block) else
        StandaloneCoroutine(newContext, active = true)
    coroutine.start(start, coroutine, block)
    return coroutine
}

async方法

  1. 该方法将会创建新的协程, 并将其将来的结果作为 [Deferred] 即延迟的实现返回。
  2. 当该方法返回的结果对象被[cancelled][Job.cancel]后, 当前正在运行的协程被取消。
  3. 可以显式指定新协程的 [context]即协程上下文对象。
  4. 请参阅 “kotlinx.coroutines” 提供的标准上下文实现的 .
/**
 * Creates new coroutine and returns its future result as an implementation of [Deferred].
 *
 * The running coroutine is cancelled when the resulting object is [cancelled][Job.cancel].
 *
 * The [context] for the new coroutine can be explicitly specified.
 * See [CoroutineDispatcher] for the standard context implementations that are provided by `kotlinx.coroutines`.
 * The [context][CoroutineScope.coroutineContext] of the parent coroutine from its [scope][CoroutineScope] may be used,
 * in which case the [Job] of the resulting coroutine is a child of the job of the parent coroutine.
 * The parent job may be also explicitly specified using [parent] parameter.
 *
 * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [DefaultDispatcher] is used.
 *
 * By default, the coroutine is immediately scheduled for execution.
 * Other options can be specified via `start` parameter. See [CoroutineStart] for details.
 * An optional [start] parameter can be set to [CoroutineStart.LAZY] to start coroutine _lazily_. In this case,,
 * the resulting [Deferred] is created in _new_ state. It can be explicitly started with [start][Job.start]
 * function and will be started implicitly on the first invocation of [join][Job.join] or [await][Deferred.await].
 *
 * @param context context of the coroutine. The default value is [DefaultDispatcher].
 * @param start coroutine start option. The default value is [CoroutineStart.DEFAULT].
 * @param parent explicitly specifies the parent job, overrides job from the [context] (if any).*
 * @param block the coroutine code.
 */
public actual fun <T> async(
    context: CoroutineContext = DefaultDispatcher,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    parent: Job? = null,
    block: suspend CoroutineScope.() -> T
): Deferred<T> {
    val newContext = newCoroutineContext(context, parent)
    val coroutine = if (start.isLazy)
        LazyDeferredCoroutine(newContext, block) else
        DeferredCoroutine<T>(newContext, active = true)
    coroutine.start(start, coroutine, block)
    return coroutine
}

需要了解的一些内容

  1. DefaultDispatcher :[launch]和[async]等标准协程生成器 默认使用的CoroutineDispatcher协程调度者,负责任务的调度,它当前的值等于 CommonPool, 但该值将来会发生变化;

  2. CommonPool :表示共享线程的公用池,作为计算密集型任务的协程调度器。当可用时, 它使用 [java.util.concurrent.ForkJoinPool], 它为其队列实现了高效的工作窃取算法, 因此, 即使在池中已经执行了每个协程恢复, 也会作为单独的任务进行调度。
    如果可用, 它将包装 “ForkJoinPool commonPool”, 并提供一个类似的共享池。

猜你喜欢

转载自blog.csdn.net/qq_21700489/article/details/79277225