协程搬运工-上下文和调度器

简介: 协程搬运工-上下文和调度器

上下文


协程总是运行在一些以 CoroutineContext 类型为代表的上下文中


调度器


协程上下文包含一个 协程调度器 (参见 CoroutineDispatcher)它确定了相关的协程在哪个线程或哪些线程上执行。协程调度器可以将协程限制在一个特定的线程执行,或将它分派到一个线程池,亦或是让它不受限地运行。


所有的协程构建器诸如 launch 和 async 接收一个可选的 CoroutineContext 参数,它可以被用来显式的为一个新协程或其它上下文元素指定一个调度器。

以下是集中函数的上下文

  1. launch:运行在父协程的上下文中
  2. launch(Dispatchers.Unconfined)将不受限的运行的在主线程中
  3. launch(Dispatchers.Default) 运行在默认调度器中
  4. launch(newSingleThreadContext("MyOwnThread"))运行在一个新线程中
  5. GlobalScope.launch使用的是Dispatchers.Default调度器


非受限调度器

Dispatchers.Default就是非受限调度器。

非受限调度器,我的理解是它不限制协程在某个父协程中运行,也就是说协程在运行过程中可以改变所运行的协程,比如如下代码

launch(Dispatchers.Unconfined) { // 非受限的——将和主线程一起工作
        println("Unconfined")//这行代码运行在主线程
        delay(500)
        println("Unconfined")//运行在单独协程中,因为调用过delay挂起过,所以在此恢复的时候协程变运行在单独协程中了
    }
复制代码

Dispatchers.Default最好不要出现在你的业务代码中,那将是麻烦的


子协程


当一个协程被其它协程在 CoroutineScope 中启动的时候, 它将通过 CoroutineScope.coroutineContext 来承袭上下文,并且这个新协程的 Job 将会成为父协程作业的 子 作业。当一个父协程被取消的时候,所有它的子协程也会被递归的取消。

当使用 GlobalScope 来启动一个协程时,则新协程的作业没有父作业。 因此它与这个启动的作用域无关且独立运作。

  1. 代码
fun main() = runBlocking {
    val job = launch {//这个就是我们要启动的父协程
        GlobalScope.launch {
            log(A)//会被调用
            delay(1000)
            log(B)//会被调用,因为这是顶级协程
        }
        launch {
            log(C)//会被调用
            delay(1000)
            log(D)//不会被调用,因为父协程被取消,子协程也会被取消
        }
    }
    delay(500)
    job.cancel()//等待500ms后取消父协程,查看两个子协程的打印情况
    delay(2000)
    log(E)
}
复制代码
  1. 日志
日志:  A
日志:  C
日志:  B
日志:  E
复制代码
  1. 结论

父协程被取消的时候内部的子协程被成功取消了,GlobalScope顶级协程没有被取消


父协程


一个父协程总是等待所有的子协程执行结束。父协程并不显式的跟踪所有子协程的启动,并且不必使用 Job.join 在最后的时候等待它们


协程命名


使用CoroutineName("v1coroutine")可以给协程命名,这在调试协程打印日志的时候非常有用

val v1 = async(CoroutineName("v1coroutine")) {
    delay(500)
    log("Computing v1")
    252
}
复制代码


组合上下文中的参数


有时我们需要在协程上下文中定义多个元素。我们可以使用 + 操作符来实现。 比如说,我们可以显式指定一个调度器来启动协程并且同时显式指定一个命名,

例如:Dispatchers.Default + CoroutineName("test")

launch(Dispatchers.Default + CoroutineName("test")) {
    println("I'm working in thread ${Thread.currentThread().name}")
}
复制代码


协程作用域


我们通过创建一个 CoroutineScope 实例来管理协程的生命周期,并使它与 activity 的生命周期相关联。CoroutineScope 可以通过 CoroutineScope() 创建或者通过MainScope() 工厂函数。前者创建了一个通用作用域,而后者为使用 Dispatchers.Main 作为默认调度器的 UI 应用程序 创建作用域

比如我们再我们的Activity中创建了一个MainScope,只需要在onDestroy中cancel协程就可以完全避免内存泄露。


两种方式能创建作用域:

CoroutineScope(Dispatchers.Default)
MainScope()
复制代码
  1. 代码
fun main() = runBlocking {
    val scope=CoroutineScope(Dispatchers.Default)
    repeat(9){
        scope.launch {
            delay(100L*it)//这里delay的秒数递增,0,100,200,300,400
            log(A)
        }
    }
    log(B)
    delay(200)
    scope.cancel()//因为这里延迟了200ms后取消,所以上面repeat中创建的协程中延迟大于200ms的将无法打印日志A
    log(C)
}
复制代码
  1. 日志
日志:  A
日志:  B
日志:  A
日志:  A
日志:  C
复制代码
  1. 结论

自定义的作用域CoroutineScope被取消后它内部所有未执行完成的协程都会被取消。



相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
相关文章
协程搬运工-组合挂起函数
协程搬运工-组合挂起函数
219 0
协程搬运工-取消与超时
协程搬运工-取消与超时
377 0
|
4月前
|
Go 调度 Python
Golang协程和Python协程用法上的那些“不一样”
本文对比了 Python 和 Go 语言中协程的区别,重点分析了调度机制和执行方式的不同。Go 的协程(goroutine)由运行时自动调度,启动后立即执行;而 Python 协程需通过 await 显式调度,依赖事件循环。文中通过代码示例展示了两种协程的实际运行效果。
209 7
|
3月前
|
数据采集 网络协议 API
协程+连接池:高并发Python爬虫的底层优化逻辑
协程+连接池:高并发Python爬虫的底层优化逻辑
|
5月前
|
数据采集 监控 调度
干货分享“用 多线程 爬取数据”:单线程 + 协程的效率反超 3 倍,这才是 Python 异步的正确打开方式
在 Python 爬虫中,多线程因 GIL 和切换开销效率低下,而协程通过用户态调度实现高并发,大幅提升爬取效率。本文详解协程原理、实战对比多线程性能,并提供最佳实践,助你掌握异步爬虫核心技术。
|
Go Python
使用python实现一个用户态协程
【6月更文挑战第28天】本文探讨了如何在Python中实现类似Golang中协程(goroutines)和通道(channels)的概念。文章最后提到了`wait_for`函数在处理超时和取消操作中的作
238 1
使用python实现一个用户态协程
|
数据库 开发者 Python
实战指南:用Python协程与异步函数优化高性能Web应用
【7月更文挑战第15天】Python的协程与异步函数优化Web性能,通过非阻塞I/O提升并发处理能力。使用aiohttp库构建异步服务器,示例代码展示如何处理GET请求。异步处理减少资源消耗,提高响应速度和吞吐量,适用于高并发场景。掌握这项技术对提升Web应用性能至关重要。
287 10
|
调度 Python
python3 协程实战(python3经典编程案例)
该文章通过多个实战案例介绍了如何在Python3中使用协程来提高I/O密集型应用的性能,利用asyncio库以及async/await语法来编写高效的异步代码。
323 0
|
数据处理 Python
深入探索:Python中的并发编程新纪元——协程与异步函数解析
【7月更文挑战第15天】Python 3.5+引入的协程和异步函数革新了并发编程。协程,轻量级线程,由程序控制切换,降低开销。异步函数是协程的高级形式,允许等待异步操作。通过`asyncio`库,如示例所示,能并发执行任务,提高I/O密集型任务效率,实现并发而非并行,优化CPU利用率。理解和掌握这些工具对于构建高效网络应用至关重要。
217 6