Kotlin - 协程中的那些关键点

554 阅读4分钟

写在前面

1.协程“非阻塞式挂起” 你真的弄懂了吗?

2.协程suspend关键字到底有多神奇?

3.协程有了launch,还要async干啥?抱小三?

4.协程真的高大上吗?

1.非阻塞式挂起

阻塞:即程序因耗时操作等原因阻止线程继续运行

非阻塞:即不阻止程序继续运行

挂起:即wait,释放已经获取到的线程资源

非阻塞式挂起:不阻止程序运行,还释放了已经获取到的线程资源

那么问题来了,你把资源都释放了我咋继续后续操作?

Are you kid me?

他到底干了啥,有人说是关键字suspend,但是但是,你看下面代码难道执行有区别吗?

//测试代码1
GlobalScope.launch(Dispatchers.Main) {
           dealprint()
        }
        
        

//测试代码2
GlobalScope.launch(Dispatchers.Main) {
          dealTask()
}
    

    suspend fun dealTask() = withContext(Dispatchers.Default){
         Log.i(TAG,"Task:")
    }
    
    suspend fun dealprint(){
        Log.i(TAG,"print:")
    }

难道只有代码2才是非阻塞式挂起?代码1不是。

说对了,代码1不是 suspend。dealprint这里的suspend还会提示:

提示这里要移除suspend,那就可能是其他的关键点了,关键点就是切换线程

launch withContext async 等

2.suspend

suspend究竟是用来做什么呢?

suspend关键字只是一个提醒,不对两个提醒

提醒1: 我要切换线程了,下边的代码在另一个线程执行

提醒2: 我只能在协程中执行,因为执行完当前suspend方法我要切回到原先的协程继续执行后续操作

3.async

async 同步

上代码

suspend fun dealAsyncTask1(): Int {
       delay(3000)
       Log.i(TAG, "dealAsyncTask1")
       return 3
   }

   suspend fun dealAsyncTask2(): Int {
       delay(2000)
       Log.i(TAG, "dealAsyncTask2")
       return 2
   }
   
   //代码一

  GlobalScope.launch(Dispatchers.Default) {
           Log.i(TAG, "dealAsyncTask--start:")
           val one =  dealAsyncTask1()
           val two =  dealAsyncTask2()
           Log.i(TAG, "dealAsyncTask:${(one + two)}")
       }
//代码二
       GlobalScope.launch(Dispatchers.Default) {
           Log.i(TAG, "dealAsyncTask--start--async:")
           val one = async { dealAsyncTask1() }
           val two = async { dealAsyncTask2() }
           Log.i(TAG, "dealAsyncTask--async:${(one.await() + two.await())}")
       }

代码一和代码二的区别是什么,结果是一样的吗?

先上日志:

07-08 19:02:08.717 30075-30127/com.matt.mattdemo I/MainActivity: dealAsyncTask--start:
07-08 19:02:08.717 30075-30128/com.matt.mattdemo I/MainActivity: dealAsyncTask--start--async:
07-08 19:02:10.737 30075-30127/com.matt.mattdemo I/MainActivity: dealAsyncTask2
07-08 19:02:11.727 30075-30127/com.matt.mattdemo I/MainActivity: dealAsyncTask1
07-08 19:02:11.727 30075-30127/com.matt.mattdemo I/MainActivity: dealAsyncTask--async:5
07-08 19:02:11.727 30075-30127/com.matt.mattdemo I/MainActivity: dealAsyncTask1
07-08 19:02:13.737 30075-30127/com.matt.mattdemo I/MainActivity: dealAsyncTask2
07-08 19:02:13.737 30075-30127/com.matt.mattdemo I/MainActivity: dealAsyncTask:5

可以看到async执行的时间比默认执行短了2s,为啥会短,这就是async的本质,加了async会让代码块程序并发执行,dealAsyncTask2和dealAsyncTask1并发执行,而不是依次执行,好,这个方法太棒了

当然还有更多的async启动模式

public enum class CoroutineStart {
		DEFAULT,
		LAZY,
		ATOMIC,
		UNDISPATCHED
}

//DEFAULT: 默认值,它会上下文立即调度线程的执行
//LAZY:它不会立即调度协程的执行,而是在需要的时候才会触发执行
//ATOMIC:原子性调度,即不会被取消
//UNDISPATCHED:也会立即调度,直到当前的第一个挂起点,这个后面讨论分发器的时候还会说

使用方式

async(start = CoroutineStart.LAZY) { dealAsyncTask1() }

]

啊,老师,我有问题,我用了这个LAZY后还是依次执行啊,并不是你那样啊?

what??


GlobalScope.launch(Dispatchers.Default) {
            Log.i(TAG, "dealAsyncTask--start:")
            val one =  dealAsyncTask1()
            val two =  dealAsyncTask2()
            Log.i(TAG, "dealAsyncTask--normal:${(one + two)}")
        }

        GlobalScope.launch(Dispatchers.Default) {
            Log.i(TAG, "dealAsyncTask--start--async:")
            val one = async(start = CoroutineStart.LAZY) { dealAsyncTask1() }
            val two = async(start = CoroutineStart.LAZY) { dealAsyncTask2() }
            Log.i(TAG, "dealAsyncTask--async:${(one.await() + two.await())}")
        }

日志:

07-08 19:10:42.157 32265-32317/com.matt.mattdemo I/MainActivity: dealAsyncTask--start:
07-08 19:10:42.157 32265-32318/com.matt.mattdemo I/MainActivity: dealAsyncTask--start--async:
07-08 19:10:45.157 32265-32318/com.matt.mattdemo I/MainActivity: dealAsyncTask1
07-08 19:10:45.157 32265-32318/com.matt.mattdemo I/MainActivity: dealAsyncTask1
07-08 19:10:47.157 32265-32321/com.matt.mattdemo I/MainActivity: dealAsyncTask2
07-08 19:10:47.157 32265-32321/com.matt.mattdemo I/MainActivity: dealAsyncTask--normal:5
07-08 19:10:47.167 32265-32321/com.matt.mattdemo I/MainActivity: dealAsyncTask2
07-08 19:10:47.167 32265-32321/com.matt.mattdemo I/MainActivity: dealAsyncTask--async:5

呃,这里还有一个问题就是await,LAZY的是按需执行,那么就是需要时才执行了,所以只有等他调用await获取结果的时候,才会执行相应的方法,所以就是依次执行了。

嗯,终于出坑了。

4.协程真的高大上吗

真香,但是香到了什么程度呢?

1.他封装了线程池,旧概念新炒,千万别被官方比线程好多少忽悠了,线程池比线程 也好

2.调度的概念真的很棒,包括语法也很棒,比rxJava的可读可用强太多了

3.效率真的没有显著提升

4.真正的效率Only使用

5.真香

感谢阅读。