转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/118093646
本文出自【赵彦军的博客】

往期精彩文章

Android Coroutines Channels

Kotlin实战指南二十:flow

Kotlin实战指南十六:Synchronized、Volatile

文章目录

  • measureTimeMillis 统计一段代码耗时
  • 使用默认顺序
  • 使用 async 并发
  • 惰性启动的 async
  • 构建async 风格的函数
  • 使用 async 的结构化并发

measureTimeMillis 统计一段代码耗时

内敛函数 measureTimeMillis{ } 可以很方便的统计一段代码执行的耗时。

使用:

GlobalScope.launch {val time = measureTimeMillis {delay(1000)Log.d("zyj-", "日志")}Log.d("zyj-", "耗时:$time")
}

输出结果:

D/zyj-: 日志
D/zyj-: 耗时:1010

使用默认顺序

定义两个耗时函数:

suspend fun doSomethingUsefulOne(): Int {delay(1000L) // 假设我们在这里做了一些有用的事return 13
}suspend fun doSomethingUsefulTwo(): Int {delay(1000L) // 假设我们在这里也做了一些有用的事return 29
}

使用默认的顺序调用:

val time = measureTimeMillis {val one = doSomethingUsefulOne()val two = doSomethingUsefulTwo()println("The answer is ${one + two}")
}
println("Completed in $time ms")

它的打印输出如下:

The answer is 42
Completed in 2017 ms

从输出结果上看,两个耗时任务是串行的,总耗时= 耗时函数1 + 耗时函数2

使用 async 并发

如果 doSomethingUsefulOnedoSomethingUsefulTwo 之间没有依赖,并且我们想更快的得到结果,让它们进行 并发 吗?这就是async 可以帮助我们的地方。

在概念上,async 就类似于 launch。它启动了一个单独的协程与其它所有的协程一起并发的工作。不同之处在于 launch 返回一个 Job 并且不附带任何结果值,而 async 返回一个 Deferred—— 一个非阻塞 future, 这代表了一个将会在稍后提供结果的 promise。你可以使用 .await()在一个延期的值上得到它的最终结果, 但是 Deferred 也是一个 Job,所以如果需要的话,你可以取消它。

val time = measureTimeMillis {val one = async { doSomethingUsefulOne() }val two = async { doSomethingUsefulTwo() }println("The answer is ${one.await() + two.await()}")
}
println("Completed in $time ms")

它的打印输出如下:

The answer is 42
Completed in 1017 ms

这里快了两倍,因为两个协程并发执行。 请注意,使用协程进行并发总是显式的。

惰性启动的 async

可选的,async 可以通过将 start 参数设置为 CoroutineStart.LAZY 而变为惰性的。 在这个模式下,只有结果通过 await 获取的时候协程才会启动,或者在 Jobstart函数调用的时候。运行下面的示例:

val time = measureTimeMillis {val one = async(start = CoroutineStart.LAZY) { doSomethingUsefulOne() }val two = async(start = CoroutineStart.LAZY) { doSomethingUsefulTwo() }// 执行一些计算one.start() // 启动第一个two.start() // 启动第二个println("The answer is ${one.await() + two.await()}")
}
println("Completed in $time ms")

它的打印输出如下:

The answer is 42
Completed in 1017 ms

因此,在先前的例子中这里定义的两个协程没有执行,但是控制权在于程序员准确的在开始执行时调用 start。我们首先 调用 one,然后调用 two,接下来等待这个协程执行完毕。

注意,如果我们只是在 println 中调用 await,而没有在单独的协程中调用 start,这将会导致顺序行为,直到 await 启动该协程 执行并等待至它结束,这并不是惰性的预期用例。 在计算一个值涉及挂起函数时,这个 async(start = CoroutineStart.LAZY)的用例用于替代标准库中的 lazy 函数。

构建async 风格的函数

我们可以定义异步风格的函数来 异步 的调用 doSomethingUsefulOnedoSomethingUsefulTwo 并使用 async 协程建造器并带有一个显式的 GlobalScope 引用。 我们给这样的函数的名称中加上“……Async”后缀来突出表明:事实上,它们只做异步计算并且需要使用延期的值来获得结果。

// somethingUsefulOneAsync 函数的返回值类型是 Deferred<Int>
fun somethingUsefulOneAsync() = GlobalScope.async {doSomethingUsefulOne()
}// somethingUsefulTwoAsync 函数的返回值类型是 Deferred<Int>
fun somethingUsefulTwoAsync() = GlobalScope.async {doSomethingUsefulTwo()
}

使用

class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)// 我们可以在协程外面启动异步执行val one = somethingUsefulOneAsync()val two = somethingUsefulTwoAsync()// 但是等待结果必须调用其它的挂起或者阻塞// 当我们等待结果的时候,这里我们使用 `GlobalScope.launch{ }` 来阻塞主线程GlobalScope.launch {println("The- answer is ${one.await()}  ${two.await()}")}}
}

这种带有异步函数的编程风格仅供参考,因为这在其它编程语言中是一种受欢迎的风格。在 Kotlin 的协程中使用这种风格是强烈不推荐的, 原因如下所述。

考虑一下如果 val one = somethingUsefulOneAsync() 这一行和 one.await() 表达式这里在代码中有逻辑错误, 并且程序抛出了异常以及程序在操作的过程中中止,将会发生什么。 通常情况下,一个全局的异常处理者会捕获这个异常,将异常打印成日记并报告给开发者,但是反之该程序将会继续执行其它操作。但是这里我们的 somethingUsefulOneAsync仍然在后台执行, 尽管如此,启动它的那次操作也会被终止。这个程序将不会进行结构化并发,如下一小节所示。

使用 async 的结构化并发

让我们使用使用 async 的并发这一小节的例子并且提取出一个函数并发的调用 doSomethingUsefulOnedoSomethingUsefulTwo 并且返回它们两个的结果之和。 由于 async 被定义为了 CoroutineScope上的扩展,我们需要将它写在作用域内,并且这是 coroutineScope 函数所提供的:

suspend fun concurrentSum(): Int = coroutineScope {val one = async { doSomethingUsefulOne() }val two = async { doSomethingUsefulTwo() }one.await() + two.await()
}

这种情况下,如果在 concurrentSum 函数内部发生了错误,并且它抛出了一个异常, 所有在作用域中启动的协程都会被取消。

val time = measureTimeMillis {println("The answer is ${concurrentSum()}")
}
println("Completed in $time ms")

从上面的 main 函数的输出可以看出,我们仍然可以同时执行这两个操作:

The answer is 42
Completed in 1017 ms

取消始终通过协程的层次结构来进行传递:

import kotlinx.coroutines.*fun main() = runBlocking<Unit> {try {failedConcurrentSum()} catch(e: ArithmeticException) {println("Computation failed with ArithmeticException")}
}suspend fun failedConcurrentSum(): Int = coroutineScope {val one = async<Int> { try {delay(Long.MAX_VALUE) // 模拟一个长时间的运算42} finally {println("First child was cancelled")}}val two = async<Int> { println("Second child throws an exception")throw ArithmeticException()}one.await() + two.await()
}

请注意,如果其中一个子协程(即 two)失败,第一个 async 以及等待中的父协程都会被取消:

Second child throws an exception
First child was cancelled
Computation failed with ArithmeticException

Android Kotlin 协程async相关推荐

  1. Android Kotlin协程和Retrofit结合使用

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/118085035 本文出自[赵彦军的博客] 往期精彩文章: Kotlin实战指南二十 ...

  2. Android - kotlin 协程极简入门

    背景 协程的作用是解决并发,并发的常见场景是多线程. "并发"和"并行"经常弄混.下面是我的理解,当然我理解也不一定是对的 "并发"是宏观上 ...

  3. kotlin协程async await的异常踩坑以及异常处理的正确姿势

    使用Kotlin来做一些异步操作相信大家都非常熟悉了,特别是结合Jetpack的一些组件,使得我们在Android开发中写异步任务非常的方便. 但是,关于在使用协程的时候,个人觉得异常处理这一块是相对 ...

  4. Android Kotlin + 协程 + Retrofit + MVVM优雅的实现网络请求(简洁!!!!)

    最近学习了Kotlin,感受就是好处太多了 欲罢不能,这其中协程这个特点处理异步非常不错,于是花了很长时间结合Retrofit封装了网络请求,感觉非常简洁好用.先看下调用方式 准备工作:Retrofi ...

  5. Kotlin 协程:简单理解 runBlocking, launch ,withContext ,async,doAsync

    前言 Kotlin的协程,本质上是一个线程框架,它可以方便的切换线程的上下文(如主线程切换到子线程/子线程切回主线程).而平时我们要想在Android Studio使用协程,先要在gradle引入协程 ...

  6. 在 Android 开发中使用 Kotlin 协程 (一) -- 初识 Kotlin 协程

    前言 最近在研究 Kotlin 协程,发现功能真的超级强大,很有用,而且很好学,如果你正在或计划使用 Kotlin 开发 Android,那么 Kotlin 协程你一定不能错过! 协程是什么? 我们平 ...

  7. android 协程,Android 上的 Kotlin 协程

    协程是一种并发设计模式,您可以在 Android 平台上使用它来简化异步执行的代码.协程是在版本 1.3 中添加到 Kotlin 的,它基于来自其他语言的既定概念. 在 Android 上,协程有助于 ...

  8. 【Kotlin 协程】Flow 异步流 ② ( 使用 Flow 异步流持续获取不同返回值 | Flow 异步流获取返回值方式与其它方式对比 | 在 Android 中使用 Flow 异步流下载文件 )

    文章目录 一.使用 Flow 异步流持续获取不同返回值 二.Flow 异步流获取返回值方式与其它方式对比 三.在 Android 中 使用 Flow 异步流下载文件 一.使用 Flow 异步流持续获取 ...

  9. 大型Android项目架构:基于组件化+模块化+Kotlin+协程+Flow+Retrofit+Jetpack+MVVM架构实现WanAndroid客户端

    前言:苟有恒,何必三更眠五更起:最无益,莫过一日曝十日寒. 前言 之前一直想写个 WanAndroid 项目来巩固自己对 Kotlin+Jetpack+协程 等知识的学习,但是一直没有时间.这里重新行 ...

最新文章

  1. 短视频个性化Push工程精进之路
  2. C和C++中include 搜索路径的一般形式以及gcc搜索头文件的路径
  3. jdk8 list转Map
  4. 京瓷m5021cdn如何设置扫描_京瓷产品让您轻松应对潮湿天气
  5. 5分钟搞定Loki告警多渠道接入
  6. Spring中Aware的用法以及实现
  7. C#LeetCode刷题之#172-阶乘后的零(Factorial Trailing Zeroes)
  8. 创建服务factory和service方法的区别
  9. Grafana中文版本 1
  10. 字母串按照字典序排序
  11. ZWrite 和ZTest
  12. Grasshopper 0.9汉化版下载 【Rhino5.0参数化插件】
  13. EJB到底是什么,真的那么神秘吗?
  14. word文档怎么压缩,word压缩大小
  15. 计算机图片怎么截图快捷键,电脑怎么截图,常见的截图快捷键
  16. 云宏金融云及虚拟化解决方案精彩亮相第十一届中国城市商业银行信息化发展创新座谈会
  17. Python 数据扩充(亮度、翻转、噪声)
  18. 关于采样率位深码率无损的一些心得
  19. MSN Messenger 7.0测试版公开推出 已经可以下载
  20. 删除电脑上重复文件的方法--好用小软件推荐

热门文章

  1. php 验证url,php过滤器filter验证邮箱、url和ip地址等
  2. 我为什么重新做起了公众号?
  3. 十九、抓包利器Charles的使用
  4. 三、IntellijIDEA开发工具,学习Java好利器
  5. 【Python金融量化 2- 100 】股票量化分析基本知识
  6. 博士申请 | 加拿大麦吉尔大学丁俊老师招收机器学习全奖博士/硕士/实习生
  7. 中文NER涨点神器!基于多元数据的双流Transformer编码模型
  8. 超大规模智能模型相关工作总结:编程实现框架、算法模型、微调技术和应用...
  9. 无监督领域迁移及文本表示学习的相关进展
  10. 数学建模第三节2020.4.17-5.3补