Kotlin协程深入理解

1.协程简介

协程在Kotlin中是一个很重要的概念,也是比较难理解的概念之一。那么协程到底是怎样的存在,那么接下来让我们好好地理一理。
根据官方文档的说法,它大概有一些特性:
1.协程是轻量级的线程,一个线程中可以同时起成百上千的协程,而不会导致资源过度占用,造成系统崩溃。
2.协程运行在线程中,协程之于线程有点类似与线程之于进程,线程需要运行在进程中,同样的协程的运行也需要具体的线程来调度。线程的运行耗时的操作会阻塞,但是协程不会,它只会挂起和恢复。
3.协程可以运行在不同的线程中,由线程调度器去切换协程运行的上下文即可。

从上面的描述,我们很容易总结协程的几个特点:轻量、高效、灵活。但这些不足以让协程成为Kotlin中最亮的崽,它的高超之处在于将异步的处理简单化,用同步的语法实现异步的逻辑,避免了多线程编程中遭遇的回调地狱。

2.协程异步处理

多线程异步逻辑 VS 协成异步逻辑
下面以获取联系人电话列表为例说明两者差异
使用多线程异步处理

//getPhones by callback
        getContacts(object : SuccessCallback {
            override fun onCallback(result: String) {
                getPhoneList(result, object : SuccessCallback {
                    override fun onCallback(result: String) {
                        print( "callback, phones result: $result \n")
                    }
                })
            }
        })
 fun getContacts(callback: SuccessCallback){
        Thread {
            run {
                Thread.sleep(2000)
                val users = "Bob, Anni, Jacky"
                callback.onCallback(users)
            }

        }.start()

    }

    fun getPhoneList(users:String, callback: SuccessCallback){
        Thread {
            run {
                Thread.sleep(2000)
                val phones = "Bob:1213, Anni:121234, Jacky:12123"
                callback.onCallback(phones)
            }

        }.start()
    }

    interface SuccessCallback{
        fun onCallback(result:String)
    }

使用协程异步处理

//getPhones by Coroutines
        runBlocking {
            val users =  getContacts()
			log(users)
            val phones = getPhones(users)
			log(phones)
            print( "coroutines, phone result: $phones \n")
		}

   suspend fun getContacts():String{
        return  withContext(Dispatchers.IO){
            delay(2000)
            log("getContacts invoke")
            "Bob, Anni, Jacky"
        }
    }


    fun log(msg:String){
        print("coroutines, $msg current thread: ${Thread.currentThread().name}\n")
    }

    suspend fun getPhones(users: String):String{
        return  withContext(Dispatchers.IO){
            delay(2000)
            log("getPhones invoke")
            "Bob:1234, Anni:12123, Jacky:121213"
        }
    }

从上面的示例代码得出如下结论:
1.多线程处理异步避免不了回调嵌套,协程处理异步则可以用同步方式实现;
2.协程借助withContext之类的操作灵活地切换线程,而多线程则需要借助Handler之类的切换线程;

多线程方式还是仅包含 onSuccess 的情况,实际情况会更复杂,因为我们还要处理异常,处理重试,处理线程调度,甚至还可能涉及多线程同步。而协程在处理异步任务时就显得舒服多了。

3.协成关键点

从上面的示例代码我们不难发现协程的一些关键点
(1)协程中调用的是使用suspend修饰的挂起函数;
(2) 挂起函数不会阻塞调用线程,可以暂停和恢复。

val users =  getContacts()
log(users)
 val phones = getPhones(users)
log(phones)

在上面使用协程获取联系人电话列表过程中有以下几点说明:

  • 表面上看起来是同步的代码,实际上也涉及到了线程切换。
  • 一行代码,切换了两个线程。
  • =左边:主线程
  • =右边:IO线程
  • 每一次从主线程到IO线程,都是一次协程挂起(suspend)
  • 每一次从IO线程到主线程,都是一次协程恢复(resume)。
  • 挂起和恢复,这是挂起函数特有的能力,普通函数是不具备的。
  • 挂起,只是将程序执行流程转移到了其他线程,主线程并未被阻塞。
    如果以上代码运行在 Android 系统,我们的 App 是仍然可以响应用户的操作的,主线程并不繁忙,这也很容易理解。

4.协程的本质

通过反编译kotlin代码编译后的.class文件,我们不难看出协程的本质
getContacts()函数的反编译结果为例,原始定义为suspend fun getContacts():String
挂起函数最终转换成下面形式,suspend去掉了,但是多个Continuation参数
public final Object getContacts(@NotNull Continuation $completion)
看看Continuation的定义,它是一个接口,这不正是我们异步处理的常规操作吗,定义一个Callback返回结果执行结果。

public interface Continuation<in T> {
    public val context: CoroutineContext
//      相当于 onSuccess     结果   
//                 ↓         ↓
    public fun resumeWith(result: Result<T>)
}

以上这个从挂起函数转换成CallBack 函数的过程,被称为:CPS 转换(Continuation-Passing-Style Transformation)。

协程以同步的方式返回执行结果又是如何实现的呢?
通过阅读反编译后的源码我们不难发现,这个过程是使用状态机完成的。

那么协程的本质可以概括为以下两点:
1.CPS转换将挂起函数转成Callback回调;
2.使用状态机完成挂起与恢复的功能机制。

5.协程作用域

协程需要运行在特定的作用域中,即CoroutineScope, 在Android架构组件中存在各种作用域,ViewModel中使用ViewModelScope,在Activity/Fragment中使用LifecycleScope等。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Kotlin程是一种轻量级的线程处理机制,它可以在不创建新线程的情况下实现异步操作。Kotlin程的优势在于它提供了一种结构化并发的方式,使得异步代码更加易于编写和维护。下面是深入理解Kotlin程的一些方法和步骤: 1. 程的基本概念:程是一种轻量级的线程处理机制,它可以在不创建新线程的情况下实现异步操作。程的本质是一种作式的多任务处理机制,它可以在同一个线程中切换执行不同的任务,从而实现异步操作。 2. 程的使用方法:在Kotlin中,程的使用方法非常简单。首先需要导入kotlinx.coroutines库,然后使用launch函数创建一个程。在程中可以使用挂起函数来实现异步操作,例如delay函数可以让程暂停一段时间。 3. 程的挂起函数:程的挂起函数是一种特殊的函数,它可以让程暂停执行,等待某个条件满足后再继续执行。在Kotlin中,常用的挂起函数包括delay函数、withContext函数和async函数等。 4. 程的上下文:程的上下文是一种特殊的对象,它包含了程的执行环境和状态信息。在Kotlin中,程的上下文可以通过CoroutineContext对象来表示,它包含了程的调度器、异常处理器和其他一些属性。 5. 程的异常处理:程的异常处理是一种特殊的机制,它可以让程在发生异常时自动恢复或者终止执行。在Kotlin中,程的异常处理可以通过try-catch语句或者CoroutineExceptionHandler对象来实现。 6. 程的取消:程的取消是一种特殊的机制,它可以让程在不需要继续执行时自动终止。在Kotlin中,程的取消可以通过cancel函数或者程作用域来实现。 下面是一个使用Kotlin程实现异步操作的例子: ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { val job = launch { delay(1000L) println("World!") } println("Hello,") job.join() } ``` 输出结果为: ``` Hello, World! ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Calvin880828

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值