zoukankan      html  css  js  c++  java
  • Kotlin 使用协程编写高效的并发程序

    概念:

    轻量级的线程

    协程允许我们在单线程模式下模拟多线程编程的效果,代码执行时的挂起与恢复完
    全是由编程语言来控制的,和操作系统无关。这种特性使得高并发程序的运行效率得到了极大的提升。

    依赖库:

    dependencies {
    ...
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.1"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1"
    }
    
    fun main() {
    GlobalScope.launch {
    println("codes run in coroutine scope")
    }
    Thread.sleep(1000)
    }
    

    借助runBlocking函数实现在协程中所有代码执行完后再结束:

    fun main() {
    runBlocking {
    println("codes run in coroutine scope")
    delay(1500)
    println("codes run in coroutine scope finished")
    }
    }
    

    多个协程

    子协程的特点是如果外层作用域的协程结束了,该作用域下的所有子协程也会一同结束。相比而言,GlobalScope.launch函数创建的永远是顶层协程,这一点和线程比较像,因为线程也没有层级这一说,永远都是顶层的。

    fun main() {
        runBlocking {
            launch {
            println("launch1")
            delay(1000)
            println("launch1 finished")
        }
        launch {
            println("launch2")
            delay(1000)
            println("launch2 finished")
            }
        }
    }
    

    suspend挂起函数关键字

    suspend关键字只能将一个函数声明成挂起函数,是无法给它提供协程作用域的。

    suspend fun printDot() {
        println(".")
        delay(1000)
    }
    

    coroutineScope挂起函数

    coroutineScope函数和runBlocking函数还有点类似,它可以保证其作用域内的所
    有代码和子协程在全部执行完之前,外部的协程会一直被挂起。

    suspend fun printDot() = coroutineScope {
        launch {
            println(".")
            delay(1000)
        }
    }
    
    fun main() {
        //协程作用域
        runBlocking {
            //子协程
            coroutineScope {
                launch {
                    for (i in 1..10) {
                        println(i)
                        delay(1000)
                    }
                }
            }
            println("coroutineScope finished")
        }
        println("runBlocking finished")
    }
    

    coroutineScope和runBlocking的区别

    coroutineScope函数只会阻塞当前协程,既不影响其他协程,也不影响任何线程,因此是不
    会造成任何性能上的问题的。

    runBlocking函数由于会挂起外部线程,如果你恰好又在主线程中当中调用它的话,那么就有可能会导致界面卡死的情况,所以不?推荐在实际项目中使用。

    实际项目中协程的使用

    val job = Job()
    val scope = CoroutineScope(job)
    scope.launch {
    	// 处理具体的逻辑
    }
    //取消协程
    job.cancel()
    

    async函数 创建协程并获取执行结果

    async函数必须在协程作用域当中才能调用,它会创建一个新的子协程并返回一个Deferred对
    象,如果我们想要获取async函数代码块的执行结果,只需要调用Deferred对象的await()方法即可

    fun main() {
        runBlocking {
            val start = System.currentTimeMillis()
            val deferred1 = async {
                delay(1000)
                5 + 5
            }
            val deferred2 = async {
                delay(1000)
                4 + 6
            }
            //两个async函数同时执行,执行完后调用await()获取结果
            println("result is ${deferred1.await() + deferred2.await()}.")
            val end = System.currentTimeMillis()
            println("cost ${end - start} milliseconds.")
        }
    }
    

    withContext()函数

    简化版的async函数

    线程参数

    Dispatchers.Default:表示会使用一种默认低并发的线程策略,当你要执行的代码属于计算密集型任务时,开启过高的并发?而可能会影响任务的运行效率。

    Dispatchers.IO:表示会使用一种较高并发的线程策略,当你要执行的代码大多数时间是在阻塞和等待中,比如说执行网络请求时,为了能够支持更高的并发数量。
    Dispatchers.Main:不会开启子线程,而是在Android主线程中执行代码,但是这个值只能在Android项目中使用,纯Kotlin程序使用这种类型的线程参数会出现错误。

    fun main() {
        runBlocking {
            val result = withContext(Dispatchers.Default) {
            5 + 5
        }
        println(result)
        }
    }
    
  • 相关阅读:
    继承中类的作用域
    访问控制与继承
    虚函数与抽象基类
    定义基类和派生类
    类成员指针
    固有的不可移植特性
    局部类
    union
    嵌套类
    枚举类型
  • 原文地址:https://www.cnblogs.com/androidsuperman/p/14825739.html
Copyright © 2011-2022 走看看