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

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 协程搬运工-上下文和调度器

上下文


协程总是运行在一些以 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被取消后它内部所有未执行完成的协程都会被取消。



相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
协程搬运工-组合挂起函数
协程搬运工-组合挂起函数
115 0
协程搬运工-取消与超时
协程搬运工-取消与超时
279 0
|
6月前
|
Go Python
使用python实现一个用户态协程
【6月更文挑战第28天】本文探讨了如何在Python中实现类似Golang中协程(goroutines)和通道(channels)的概念。文章最后提到了`wait_for`函数在处理超时和取消操作中的作
52 1
使用python实现一个用户态协程
|
3月前
|
调度 Python
python3 协程实战(python3经典编程案例)
该文章通过多个实战案例介绍了如何在Python3中使用协程来提高I/O密集型应用的性能,利用asyncio库以及async/await语法来编写高效的异步代码。
22 0
|
5月前
|
数据库 开发者 Python
实战指南:用Python协程与异步函数优化高性能Web应用
【7月更文挑战第15天】Python的协程与异步函数优化Web性能,通过非阻塞I/O提升并发处理能力。使用aiohttp库构建异步服务器,示例代码展示如何处理GET请求。异步处理减少资源消耗,提高响应速度和吞吐量,适用于高并发场景。掌握这项技术对提升Web应用性能至关重要。
86 10
|
5月前
|
数据处理 Python
深入探索:Python中的并发编程新纪元——协程与异步函数解析
【7月更文挑战第15天】Python 3.5+引入的协程和异步函数革新了并发编程。协程,轻量级线程,由程序控制切换,降低开销。异步函数是协程的高级形式,允许等待异步操作。通过`asyncio`库,如示例所示,能并发执行任务,提高I/O密集型任务效率,实现并发而非并行,优化CPU利用率。理解和掌握这些工具对于构建高效网络应用至关重要。
52 6
|
5月前
|
大数据 数据处理 API
性能飞跃:Python协程与异步函数在数据处理中的高效应用
【7月更文挑战第15天】在大数据时代,Python的协程和异步函数解决了同步编程的性能瓶颈问题。同步编程在处理I/O密集型任务时效率低下,而Python的`asyncio`库支持的异步编程利用协程实现并发,通过`async def`和`await`避免了不必要的等待,提升了CPU利用率。例如,从多个API获取数据,异步方式使用`aiohttp`并发请求,显著提高了效率。掌握异步编程对于高效处理大规模数据至关重要。
54 4
|
5月前
|
设计模式 机器学习/深度学习 测试技术
设计模式转型:从传统同步到Python协程异步编程的实践与思考
【7月更文挑战第15天】探索从同步到Python协程异步编程的转变,异步处理I/O密集型任务提升效率。async/await关键词定义异步函数,asyncio库管理事件循环。面对挑战,如思维转变、错误处理和调试,可通过逐步迁移、学习资源、编写测试和使用辅助库来适应。通过实践和学习,开发者能有效优化性能和响应速度。
54 3
|
5月前
|
调度 Python
揭秘Python并发编程核心:深入理解协程与异步函数的工作原理
【7月更文挑战第15天】Python异步编程借助协程和async/await提升并发性能,减少资源消耗。协程(async def)轻量级、用户态,便于控制。事件循环,如`asyncio.get_event_loop()`,调度任务执行。异步函数内的await关键词用于协程间切换。回调和Future对象简化异步结果处理。理解这些概念能写出高效、易维护的异步代码。
61 2