xxx网站建设策划书范文,商业性质网站设计,网站后台维护技能,重庆高端网站设计公司点击查看#xff1a;组合挂起函数 中文官网
点击查看#xff1a;组合挂起函数 英文文档
默认顺序调用 假设我们在不同的地方定义了两个进行某种调用远程服务或者进行计算的挂起函数。我们只假设它们都是有用的#xff0c;但是实际上它们在这个示例中只是为了该目的而延迟了…点击查看组合挂起函数 中文官网
点击查看组合挂起函数 英文文档
默认顺序调用 假设我们在不同的地方定义了两个进行某种调用远程服务或者进行计算的挂起函数。我们只假设它们都是有用的但是实际上它们在这个示例中只是为了该目的而延迟了一秒钟 import kotlinx.coroutines.*
import kotlin.system.measureTimeMillisfun main() runBlocking {val time measureTimeMillis {val one doSomethingUsefulOne()val two doSomethingUsefulTwo()println(The answer is ${one two})}println(Completed in $time ms)
}suspend fun doSomethingUsefulOne(): Int {delay(1000L) // 假设我们在这里做了一些有用的事return 13
}suspend fun doSomethingUsefulTwo(): Int {delay(1000L) // 假设我们在这里也做了一些有用的事return 29
}如果需要按 顺序 调用它们我们接下来会做什么——首先调用 doSomethingUsefulOne 接下来 调用 doSomethingUsefulTwo并且计算它们结果的和吗 实际上如果我们要根据第一个函数的结果来决定是否我们需要调用第二个函数或者决定如何调用它时我们就会这样做。 我们使用普通的顺序来进行调用因为这些代码是运行在协程中的只要像常规的代码一样 顺序 都是默认的。下面的示例展示了测量执行两个挂起函数所需要的总时间 运行结果 使用 async 并发 如果 doSomethingUsefulOne 与 doSomethingUsefulTwo 之间没有依赖并且我们想更快的得到结果让它们进行 并发 吗这就是 async 可以帮助我们的地方。 在概念上async 就类似于 launch。它启动了一个单独的协程这是一个轻量级的线程并与其它所有的协程一起并发的工作。不同之处在于 launch 返回一个 Job 并且不附带任何结果值而 async 返回一个 Deferred —— 一个轻量级的非阻塞 future 这代表了一个将会在稍后提供结果的 promise。可以使用 .await() 在一个延期的值上得到它的最终结果 但是 Deferred 也是一个 Job所以如果需要的话你可以取消它。 import kotlinx.coroutines.*
import kotlin.system.measureTimeMillisfun main() runBlocking {val time measureTimeMillis {val one async { doSomethingUsefulOne() }val two async { doSomethingUsefulTwo() }println(The answer is ${one.await() two.await()})}println(Completed in $time ms)
}suspend fun doSomethingUsefulOne(): Int {delay(1000L) // 假设我们在这里做了一些有用的事return 13
}suspend fun doSomethingUsefulTwo(): Int {delay(1000L) // 假设我们在这里也做了一些有用的事return 29
}运行结果 这里快了两倍因为两个协程并发执行。 请注意使用协程进行并发总是显式的。 惰性启动的 async 可选的async 可以通过将 start 参数设置为 CoroutineStart.LAZY 而变为惰性的。 在这个模式下只有结果通过 await 获取的时候协程才会启动或者在 Job 的 start 函数调用的时候。运行下面的示例 import kotlinx.coroutines.*
import kotlin.system.measureTimeMillisfun main() runBlocking {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)}suspend fun doSomethingUsefulOne(): Int {delay(1000L) // 假设我们在这里做了一些有用的事return 13
}suspend fun doSomethingUsefulTwo(): Int {delay(1000L) // 假设我们在这里也做了一些有用的事return 29
}运行结果 因此在先前的例子中这里定义的两个协程没有执行但是控制权在于程序员准确的在开始执行时调用 start。我们首先 调用 one然后调用 two接下来等待这个协程执行完毕。 注意如果我们只是在 println 中调用 await而没有在单独的协程中调用 start这将会导致顺序行为直到 await 启动该协程 执行并等待至它结束这并不是惰性的预期用例。 在计算一个值涉及挂起函数时这个 async(start CoroutineStart.LAZY) 的用例用于替代标准库中的 lazy 函数。 async 风格的函数 我们可以定义异步风格的函数来 异步 的调用 doSomethingUsefulOne 和 doSomethingUsefulTwo 并使用 async 协程建造器并带有一个显式的 GlobalScope 引用。 我们给这样的函数的名称中加上“……Async”后缀来突出表明事实上它们只做异步计算并且需要使用延期的值来获得结果。 import kotlinx.coroutines.*
import kotlin.system.measureTimeMillis// 注意在这个示例中我们在 main 函数的右边没有加上 runBlocking
fun main() {val time measureTimeMillis {// 我们可以在协程外面启动异步执行val one somethingUsefulOneAsync()val two somethingUsefulTwoAsync()// 但是等待结果必须调用其它的挂起或者阻塞// 当我们等待结果的时候这里我们使用 runBlocking { …… } 来阻塞主线程runBlocking {println(The answer is ${one.await() two.await()})}}println(Completed in $time ms)
}//注意这些 xxxAsync 函数不是 挂起 函数。它们可以在任何地方使用。
//然而它们总是在调用它们的代码中意味着异步这里的意思是 并发 执行。// somethingUsefulOneAsync 函数的返回值类型是 DeferredInt
fun somethingUsefulOneAsync() GlobalScope.async {doSomethingUsefulOne()
}// somethingUsefulTwoAsync 函数的返回值类型是 DeferredInt
fun somethingUsefulTwoAsync() GlobalScope.async {doSomethingUsefulTwo()
}这种带有异步函数的编程风格仅供参考因为这在其它编程语言中是一种受欢迎的风格。在 Kotlin 的协程中使用这种风格是强烈不推荐的 原因如下所述。 考虑一下如果 val one somethingUsefulOneAsync() 这一行和 one.await() 表达式这里在代码中有逻辑错误 并且程序抛出了异常以及程序在操作的过程中中止将会发生什么。 通常情况下一个全局的异常处理者会捕获这个异常将异常打印成日记并报告给开发者但是反之该程序将会继续执行其它操作。但是这里我们的 somethingUsefulOneAsync 仍然在后台执行 尽管如此启动它的那次操作也会被终止。这个程序将不会进行结构化并发如下一小节所示。 使用 async 的结构化并发 让我们使用使用 async 的并发这一小节的例子并且提取出一个函数并发的调用 doSomethingUsefulOne 与 doSomethingUsefulTwo 并且返回它们两个的结果之和。 由于 async 被定义为了 CoroutineScope 上的扩展我们需要将它写在作用域内并且这是 coroutineScope 函数所提供的 suspend fun concurrentSum(): Int coroutineScope {val one async { doSomethingUsefulOne() }val two async { doSomethingUsefulTwo() }one.await() two.await()
}这种情况下如果在 concurrentSum 函数内部发生了错误并且它抛出了一个异常 所有在作用域中启动的协程都会被取消。 import kotlinx.coroutines.*
import kotlin.system.measureTimeMillisfun main() runBlocking {val time measureTimeMillis {println(The answer is ${concurrentSum()})}println(Completed in $time ms)
}// 由于 async 被定义为了 CoroutineScope 上的扩展我们需要将它写在作用域内并且这是 coroutineScope 函数所提供的
suspend fun concurrentSum(): Int coroutineScope {val one async { doSomethingUsefulOne() }val two async { doSomethingUsefulTwo() }one.await() two.await()
}suspend fun doSomethingUsefulOne(): Int {delay(1000L) // 假设我们在这里做了一些有用的事return 13
}suspend fun doSomethingUsefulTwo(): Int {delay(1000L) // 假设我们在这里也做了一些有用的事return 29
}从上面的 main 函数的输出可以看出我们仍然可以同时执行这两个操作 运行结果 取消始终通过协程的层次结构来进行传递 fun main() runBlockingUnit {try {failedConcurrentSum()} catch (e: ArithmeticException) {println(Computation failed with ArithmeticException 异常信息${e.toString()})}//Second child throws an exception//First child was cancelled//Computation failed with ArithmeticException//请注意如果其中一个子协程即 two失败第一个 async 以及等待中的父协程都会被取消
}suspend fun failedConcurrentSum(): Int coroutineScope {val one asyncInt {try {delay(Long.MAX_VALUE) // 模拟一个长时间的运算42} finally {println(First child was cancelled)}}val two asyncInt {println(Second child throws an exception)throw ArithmeticException()}one.await() two.await()
}请注意如果其中一个子协程即 two失败第一个 async 以及等待中的父协程都会被取消 运行结果