美文网首页
Kotlin - 协程中的那些关键点

Kotlin - 协程中的那些关键点

作者: jiagf | 来源:发表于2020-07-09 14:33 被阅读0次

    ### 写在前面

    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还会提示:

    ![](https://user-gold-cdn.xitu.io/2020/5/23/17241c5bab975416?w=674&h=123&f=png&s=12837)

    提示这里要移除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.真香

    感谢阅读。

    相关文章

      网友评论

          本文标题:Kotlin - 协程中的那些关键点

          本文链接:https://www.haomeiwen.com/subject/eitscktx.html