Kotlin协程(一),已拿到offer

本文探讨了CoroutineScope在Android开发中的应用,介绍了如何通过async和concurrentSum实现结构化并发,以及调度器、流(如Flow)和Channel在并发控制中的作用。同时涵盖了异常处理、竞态与并发控制的最佳实践,适合深入理解异步编程在Android中的实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 ```
  • coroutineScope 实现结构化并发。asyncCoroutineScope 的扩展函数,因此可以直接用coroutineScope 抽取。

    fun main() = runBlocking {
        val time = measureTimeMillis {
            println("The answer is ${concurrentSum()}")
        }
        println("Completed in $time ms")
    }
    
    suspend fun concurrentSum() = coroutineScope {
        val one = async { doOne() }
        val two = async { doTwo() }
        one.await() + two.await()
    }
    
    suspend fun doOne(): Int {
        delay(1000L) // 假设我们在这里做了一些有用的事
        return 13
    }
    
    suspend fun doTwo(): Int {
        delay(1000L) // 假设我们在这里做了一些有用的事
        return 29
    } 
    
调度器
  • 协程调度器确定了哪些线程或与线程相对应的协程执⾏,将协程限制在⼀个特定的线程执⾏,或将它分派到⼀个线程池,亦或是让它不受限地运⾏。
    • launch { } 不传参启动了承袭的上下⽂调度器,

    • Dispatchers.Unconfined 是⾮受限调度器,调⽤时启动了⼀个协程,恢复线程中的协程由被调⽤的挂起函数来决定

    • Dispatchers.DefaultGlobalScope.launch {},⽤共享的后台线程池

    • ExecutorCoroutineDispatcher 启动了⼀个新的线程

      fun main() = runBlocking<Unit> {
          launch {
              print("main runBlocking        I'm working in thread ${Thread.currentThread().name} \n")
          }
          launch(Dispatchers.Unconfined) {
              print("Unconfined              I'm working in thread ${Thread.currentThread().name} \n")
          }
          launch(Dispatchers.Default) {
              print("Default                 I'm working in thread ${Thread.currentThread().name} \n")
          }
          launch(newSingleThreadContext("MyOwnThread")) {
              print("newSingleThreadContext  I'm working in thread ${Thread.currentThread().name} \n")
          }
      } 
      
流 Flow
  • Flow 类似Java8当中的 StreamFlow 对异步支持更加友好

  • 流使用emit 函数 发射 值,使用 collect 函数收集值,函数不再标有 suspend 修饰符

    fun simple(): Flow<Int> = flow {
        for (i in 1..3) {
            delay(1000)
            emit(i)
        }
    }
    
    fun main() = runBlocking<Unit> {
        launch {
            for (k in 1..3) {
                println("I'm not blocked $k")
                delay(1000)
            }
        }
        simple().collect { value -> println(value) }
    } 
    
  • 创建流

    • flow {} 构造器

      fun simple(): Flow<Int> = flow {
          for (i in 1..3) {
              delay(1000)
              emit(i)
          }
      } 
      
    • flowOf构建器定义了一个发射固定值集的流

      fun simple(): Flow<Int> = flowOf(1, 2, 3) 
      
    • 使用 .asFlow() 扩展函数,可以将各种集合与序列转换为流

      (1..3).asFlow().collect { value -> println(value) } 
      
    • 常用函数 mapfiltertransformtake

    • 末端操作collecttoListtoSetfirstsinglereduceflod

    • 其他函数flowOn()更改上下文buffer()缓冲conflate()合并

通道 Channel
  • 通道提供了一种在流中传输值的方法

  • Channel提供挂起的sendreceive

    @Test
    fun test_channel() =  runBlocking {
        val channel = Channel<Int>()
        launch {
            // this might be heavy CPU-consuming computation or async logic, we'll just send five squares
            for (x in 1..5) channel.send(x * x)
        }
        // here we print five received integers:
        repeat(5) { println(channel.receive()) }
        println("Done!")
    } 
    
  • Channel可以保证所有先前发送出去的元素都在通道关闭前被接收到

  • Channel实现自SendChannelReceiveChannel

异常处理
  • 协程构建器有两种形式:自动传播异常(launchactor)或向用户暴露异常(asyncproduce),前者这类构建器将异常视为未捕获异常,直接抛出,后者依赖用户来最终消费异常

    fun test_channel() =  runBlocking {
        val job = GlobalScope.launch { // launch 根协程
            println("Throwing exception from launch")
            throw IndexOutOfBoundsException() // 我们将在控制台打印 Thread.defaultUncaughtExceptionHandler
        }
        job.join()
        println("Joined failed job")
        val deferred = GlobalScope.async { // async 根协程
            println("Throwing exception from async")
            throw ArithmeticException() // 没有打印任何东西,依赖用户去调用等待
        }
        try {
            deferred.await()
            println("Unreached")
        } catch (e: ArithmeticException) {
            println("Caught ArithmeticException")
        }
    } 
    
竞态与并发
  • 协程可用多线程调度器并发执行,需要考虑同步访问共享的可变状态

  • 方法一:对线程、协程都有效的常规解决方法,使用线程安全的数据类型

    suspend fun massiveRun(action: suspend () -> Unit) {
        val n = 100  // 启动的协程数量
        val k = 1000 // 每个协程重复执行同一动作的次数
        val time = measureTimeMillis {
            coroutineScope { // 协程的作用域
                repeat(n) {
                    launch {
                        repeat(k) { action() }
                    }
                }
            }
        }
        println("Completed ${n * k} actions in $time ms")
    }
    
    var counter = AtomicInteger()
    
    @Test
    fun test_channel() = runBlocking {
        withContext(Dispatchers.Default) {
            massiveRun {
                counter.incrementAndGet()
            }
        }
        println("Counter = $counter")
    } 
    
  • 方法二: 对特定共享状态的所有访问权都限制在单个线程中

    suspend fun massiveRun(action: suspend () -> Unit) {
        val n = 100  // 启动的协程数量
        val k = 1000 // 每个协程重复执行同一动作的次数
        val time = measureTimeMillis {
            coroutineScope { // 协程的作用域
                repeat(n) {
                    launch {
                        repeat(k) { action() }
                    }
                }
            }
        }
        println("Completed ${n * k} actions in $time ms")
    }
    
    val counterContext = newSingleThreadContext("CounterContext")
    var counter = 0
    
    @Test
    fun test_channel() = runBlocking {
        withContext(Dispatchers.Default) {
            massiveRun {
                withContext(counterContext) {
                    counter++
                }
            }
        }
        println("Counter = $counter")
    } 
    
  • 方法三:将线程限制是在更大段代码中执行的

    suspend fun massiveRun(action: suspend () -> Unit) {
        val n = 100  // 启动的协程数量
        val k = 1000 // 每个协程重复执行同一动作的次数
        val time = measureTimeMillis {
            coroutineScope { // 协程的作用域
                repeat(n) {
                    launch {
                        repeat(k) { action() }
                    }
                }
            }
        }
        println("Completed ${n * k} actions in $time ms")
    }
     
    val counterContext = newSingleThreadContext("CounterContext")
    var counter = 0
    
    @Test
    fun test_channel() = runBlocking {
        withContext(counterContext) {
            massiveRun {
                counter++
            }
        }
        println("Counter = $counter")
    } 
    
  • 方法四: 互斥锁

    suspend fun massiveRun(action: suspend () -> Unit) {
        val n = 100  // 启动的协程数量
        val k = 1000 // 每个协程重复执行同一动作的次数
        val time = measureTimeMillis {
            coroutineScope { // 协程的作用域
                repeat(n) {
                    launch {
                        repeat(k) { action() }
                    }
                }
            }
        }
        println("Completed ${n * k} actions in $time ms")
    }
    
    val mutex = Mutex()
    var counter = 0
    
    @Test
    fun test_channel() = runBlocking {
        withContext(Dispatchers.Default) {
            massiveRun {
                mutex.withLock {
                    counter++
                }
            }
        }
        println("Counter = $counter")
    } 
    
  • 方法五: 使用Actors结合通道,区分加数据和取数据,一个 actor 是一个协程

    suspend fun massiveRun(action: suspend () -> Unit) {
        val n = 100  // 启动的协程数量
        val k = 1000 // 每个协程重复执行同一动作的次数
        val time = measureTimeMillis {
            coroutineScope { // 协程的作用域
                repeat(n) {
                    launch {
                        repeat(k) { action() }
                    }
                }
            }
        }
        println("Completed ${n * k} actions in $time ms")
    }
    
    fun CoroutineScope.counterActor() = actor<CounterMsg> {
        var counter = 0 // actor 状态
        for (msg in channel) { // 即将到来消息的迭代器
            when (msg) {
                is IncCounter -> counter++
                is GetCounter -> msg.response.complete(counter)
            }
        }
    }
    

最后

针对Android程序员,我这边给大家整理了一些资料,包括不限于高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!

CodeChina开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》

往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、混合式开发(ReactNative+Weex)全方面的Android进阶实践技术,群内还有技术大牛一起讨论交流解决问题。

技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!**

CodeChina开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》

往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、混合式开发(ReactNative+Weex)全方面的Android进阶实践技术,群内还有技术大牛一起讨论交流解决问题。

[外链图片转存中…(img-y1B3iLUo-1630851049662)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值