V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
liusd
V2EX  ›  Kotlin

我与 Kotlin 的爱恨情仇之浅谈 async/await

  •  
  •   liusd · 2017-05-26 15:04:25 +08:00 · 9163 次点击
    这是一个创建于 2771 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我与 Kotlin 的爱恨情仇之浅谈 async/await

    We all know that blocking is bad under a high load, that polling is a no-go, and the world is becoming more and more push-based and asynchronous. Many languages (starting with C# in 2012) support asynchronous programming through dedicated language constructs such as async/await keywords. In Kotlin, we generalized this concept so that libraries can define their own versions of such constructs, and async is not a keyword, but simply a function.

    写了前几篇文章之后,今天回来在想给大家聊点什么呢?整理文件的发现了一张照片,让我想起到了这个话题,至于是什么照片,不妨听我慢慢道来。

    async/await 是什么?

    我不知道你是否写过 c# ,不 严格意义上来说,是写过 2012 年之后的 c#,如果写过,那么 OK,我想这篇文章,你可以直接翻到最后啦,如果没有,那么我倒是冒昧的讲讲。

    Kotlin 1.1 版本更新中 ,介绍了 async/await 的基本用法。在文章开头我也引用了文中的描述。 Kotlin1.1 版本中引入了这个概念,可以自行实现,比如用 RX 来实现。

    从字面意思,async 异步, await 等待 ,就能看出来是为了解决异步任务的难题。

    我爱 async/await

    真的很爱,因为异步任务到处可见,一个提交表单,又或是加载一张图片,又或是普通的读写磁盘,都是非常耗时的。为了改善用户体验,往往我们会把这些耗时的 Task 放在后台 background 等事情处理好之后,回调给主线程更新视图。

    那么在没有 async/await 的时候,我们 Android 怎么活下来的呢?

    • asynctask 大概长这个样子:
     private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
         protected Long doInBackground(URL... urls) {
             int count = urls.length;
             long totalSize = 0;
             for (int i = 0; i < count; i++) {
                 totalSize += Downloader.downloadFile(urls[i]);
                 publishProgress((int) ((i / (float) count) * 100));
                 // Escape early if cancel() is called
                 if (isCancelled()) break;
             }
             return totalSize;
         }
    
         protected void onProgressUpdate(Integer... progress) {
             setProgressPercent(progress[0]);
         }
    
         protected void onPostExecute(Long result) {
             showDialog("Downloaded " + result + " bytes");
         }
     }
    
    

    别哭,当年我们就是这么过来的。但遇到了太多的坑,这里就展开了的。

    • Java Runnable & Android Handler

      配合 ThreadPoolExecutor 确实可以解决大量问题,任务调度自己处理,再配合 Handler 来切换到主线程,完全可以满足日常需求。but 使用起来,还是很不爽,比较繁琐。

    • Java Future & Android Handler

      Runnable 大相径庭,这里就不在展开了的,具体可以看文档 [《 Future 》]( https://developer.android.com/reference/java/util/concurrent/Future.html

    那么有了 async/await 之后, 现在呢?

     fun main(args: Array<String>) {
        val future = async<String> {
            (1..5).map {
                await(startLongAsyncOperation(it)) // suspend while the long method is running
            }.joinToString("\n")
        }
    
        println(future.get())
    }
    

    async 是一个异步的 blok, 如果你不懂 blok,可以等会去看看我之前的一篇关于 block 的介绍 《我与 Kotlin 的爱恨情仇之浅谈 block 》。简单的说就是后面跟了一个 代码块,返回的是一个字符串类型。 block 里面做了一个简单的 一个 map 操作,每次循环都执行 await 等待的耗时操作。 如果在没有 async/await 出来之前,这里确实很难写到这么简洁。

    我不爱 async/await

    No, 到了这个节点,只是一个形式, 我非常喜欢这种简洁方式。非要让我说一个不爱的理由,那么我只能说:“ hi, 你为什么出来的这么晚???,以至于到现在我项目中还没有用到”。

    写在最后

    为什么会提到这个话题,只是因为整理照片的时候发现了以前痛苦的往事。 2014 年 有幸 去参加了 微软马拉松比赛c# 一个只是当年大学折腾过 ASP.NET 和被折磨到哭的ADO.NET, 尤其是后者往事不堪回首。如果您折磨过,请在楼下评论去按个 1。然而还是被公司强行带到微软 园区参加比赛,各种苦,因为完全没有接触过 WP

    还好 有幸 拿了第二名。

    但这次比赛,让我 真的有幸的接触了 2012 一年以后的.NET,完全是另外一个世界啦。写起来太爽了的。其中就包括 async/await (虽然内部实现还是 task), 所以当我看到 Kotlin 1.1 版本更新介绍的时候,WOW, 这不是当年的 .Net嘛, Kotlin 你终于也有了的哦。开心。

    《查看原文》

    23 条回复    2017-05-27 22:56:51 +08:00
    abbenyyy
        1
    abbenyyy  
       2017-05-26 15:33:22 +08:00
    那么对比 RxJava 如何?最近用 RxJava2 简直上瘾,事务流式处理太爽了。
    laxenade
        2
    laxenade  
       2017-05-26 15:33:28 +08:00 via Android
    终于有一个是 scala 里没有的了
    longaiwp
        3
    longaiwp  
       2017-05-26 16:46:42 +08:00
    看起来算是前辈了
    james
        4
    james  
       2017-05-26 17:15:59 +08:00
    @laxenade Scala 里面的 future 结合 for 本质是一样的呀,只是语法不一样。
    `for {a <- aFuture, b <- bFuture} yield a + b`
    ezreal
        5
    ezreal  
       2017-05-26 20:36:53 +08:00 via iPhone
    js 里都有
    iFlicker
        6
    iFlicker  
       2017-05-26 20:55:02 +08:00 via Android
    同想知道对比 RxJava,看起来简洁一些
    liusd
        7
    liusd  
    OP
       2017-05-26 21:57:25 +08:00
    @longaiwp 只是年纪比较大了而已。晚上下班回来跟大家一起唠唠嗑。
    liusd
        8
    liusd  
    OP
       2017-05-26 21:58:40 +08:00
    @ezreal 这个是个趋势。
    liusd
        9
    liusd  
    OP
       2017-05-26 21:59:20 +08:00
    @abbenyyy 啊哈 可以考虑一起用嘛。
    limhiaoing
        10
    limhiaoing  
       2017-05-26 22:04:16 +08:00
    当年也是因为 async/await 这个语法糖学的 C#。
    limhiaoing
        11
    limhiaoing  
       2017-05-26 22:14:22 +08:00
    @james
    你这个是 generator 吧? 感觉和 async 还是有些区别的。
    james
        12
    james  
       2017-05-26 22:36:13 +08:00
    @limhiaoing 本质是一样的。Generator 还更加灵活强大,async 和 await 可以认为是语法糖。你看 ES7 里面的 async/await 也是通过 es6 的 generator 来实现的。我写 JS 也都会用上 async/await,可写 scala 用它强大的 for 语法基本差不多。
    7sDream
        13
    7sDream  
       2017-05-27 01:20:47 +08:00
    我记得看过一个 PPT 说 Kotlin 的关注并发但决定并不拘泥与某一方式,编译器是通过把 suspend function 转换成状态机来实现的,能够支持各种不同方式……

    比如这里说的 ASync/AWait,Promise/Future 之类,还可以用 go/clojure 使用的 CSP 模型,也就是用 Channel 通信;还有 erlang/elixir 的无锁 actor 模型好像也行,当然 Java 的 Thread/Mutex 也可以……

    反正看上去很厉害的样子……

    1.1 里带的这个“官方”并发库里就有很多子库,提供了很多实现的例子,貌似 RxJava 的辅助工具也有一些: https://github.com/Kotlin/kotlinx.coroutines
    SoloCompany
        14
    SoloCompany  
       2017-05-27 02:26:50 +08:00
    如果你有关注,在去年发布 1.0 的时候,1.1 的蓝图就已经规划好了,其中 coroutine 就是重点中的重点

    至于语法糖,es7 那才叫语法糖,连 promise 都包不住完全暴露出来,对比一下 kotlin 的 suspendable function 和 es7 的 async function 不难发现它们有本质的区别,es7 里面的 await 是关键字,并且是强制的,如果你忘记写了,不管所在的 closure 环境是否 async function,得到的都将是个 promise,这使得同步代码转异步代码的难度以及调试的难度都加大了; kotlin 则不存在这个问题,因为压根就没有 await 关键字,所有 suspendable function 返回都是异步的
    kimown
        15
    kimown  
       2017-05-27 07:31:27 +08:00 via Android
    在 io 大会之前,v2 上就没看到 kotlin 的文章
    liusd
        16
    liusd  
    OP
       2017-05-27 11:31:11 +08:00
    @kimown 原因是 我以为大家都知道有这么新的 JVM 语言。。。结果 IO 大会之后才炸开锅了的。
    sagaxu
        17
    sagaxu  
       2017-05-27 13:21:22 +08:00
    @liusd 去年我就跑线上了,不过我是用在服务端,不是 android
    sagaxu
        18
    sagaxu  
       2017-05-27 13:22:29 +08:00
    @james 从能不能实现逻辑的角度看,scala 也可以看作是 Java 的语法糖
    sosloop
        19
    sosloop  
       2017-05-27 17:05:19 +08:00 via Android
    硬是把白话文写成了古文
    joesonw
        20
    joesonw  
       2017-05-27 17:27:37 +08:00
    @SoloCompany C#也是语法糖咯? 不 await 返回的是 Task<>. 你没搞清楚 async/await 是为了什么. 我可以先执行一个异步方法, 但我此时不需要结果, 可以先执行其他的代码, 最后需要的时候再 await, 如果此时任务已经跑完了就直接返回结果.
    liusd
        21
    liusd  
    OP
       2017-05-27 20:48:19 +08:00
    @chenpipguge 哈哈哈哈哈
    liusd
        22
    liusd  
    OP
       2017-05-27 20:49:26 +08:00
    CodingPuppy
        23
    CodingPuppy  
       2017-05-27 22:56:51 +08:00
    @kimown #15 说实话,你 out 了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5378 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 06:59 · PVG 14:59 · LAX 22:59 · JFK 01:59
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.