在kotlinx。协程库,您可以使用启动(使用join)或异步(使用await)启动新的协程。它们之间的区别是什么?
当前回答
Launch和async用于启动新的协程。但是,他们以不同的方式来执行。
我想展示一个非常基本的例子,这将帮助你很容易地理解差异
发射
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btnCount.setOnClickListener {
pgBar.visibility = View.VISIBLE
CoroutineScope(Dispatchers.Main).launch {
val currentMillis = System.currentTimeMillis()
val retVal1 = downloadTask1()
val retVal2 = downloadTask2()
val retVal3 = downloadTask3()
Toast.makeText(applicationContext, "All tasks downloaded! ${retVal1}, ${retVal2}, ${retVal3} in ${(System.currentTimeMillis() - currentMillis)/1000} seconds", Toast.LENGTH_LONG).show();
pgBar.visibility = View.GONE
}
}
// Task 1 will take 5 seconds to complete download
private suspend fun downloadTask1() : String {
kotlinx.coroutines.delay(5000);
return "Complete";
}
// Task 1 will take 8 seconds to complete download
private suspend fun downloadTask2() : Int {
kotlinx.coroutines.delay(8000);
return 100;
}
// Task 1 will take 5 seconds to complete download
private suspend fun downloadTask3() : Float {
kotlinx.coroutines.delay(5000);
return 4.0f;
}
}
在这个例子中,我的代码下载3个数据点击btnCount按钮,并显示pgBar进度条,直到所有下载完成。有3个挂起函数downloadTask1(), downloadTask2()和downloadTask3()用于下载数据。为了模拟它,我在这些函数中使用了delay()。这些函数分别等待5秒,8秒和5秒。
因为我们已经使用launch来启动这些挂起函数,所以launch将依次执行它们(一个接一个)。这意味着,downloadTask2()将在downloadTask1()完成后启动,而downloadTask3()将仅在downloadTask2()完成后启动。
在输出截图Toast中,完成所有3个下载的总执行时间是5秒+ 8秒+ 5秒= 18秒
异步
正如我们所看到的,启动会依次执行所有3个任务。完成所有任务的时间是18秒。
如果这些任务是独立的,并且不需要其他任务的计算结果,我们可以让它们并行运行。它们将同时启动并在后台并发运行。这可以通过异步来完成。
async返回一个deferred <T>类型的实例,其中T是暂停函数返回的数据类型。例如,
downloadTask1()将返回Deferred<String>,因为String是函数的返回类型 downloadTask2()将返回Deferred<Int>,因为Int是函数的返回类型 downloadTask3()将返回Deferred<Float>,因为Float是函数的返回类型
我们可以使用类型为Deferred<T>的async的返回对象来获取T类型的返回值。这可以通过await()调用来完成。查看下面的示例代码
btnCount.setOnClickListener {
pgBar.visibility = View.VISIBLE
CoroutineScope(Dispatchers.Main).launch {
val currentMillis = System.currentTimeMillis()
val retVal1 = async(Dispatchers.IO) { downloadTask1() }
val retVal2 = async(Dispatchers.IO) { downloadTask2() }
val retVal3 = async(Dispatchers.IO) { downloadTask3() }
Toast.makeText(applicationContext, "All tasks downloaded! ${retVal1.await()}, ${retVal2.await()}, ${retVal3.await()} in ${(System.currentTimeMillis() - currentMillis)/1000} seconds", Toast.LENGTH_LONG).show();
pgBar.visibility = View.GONE
}
这样,我们就同时启动了所有3个任务。因此,我要完成的总执行时间只有8秒,这是downloadTask2()的时间,因为它是所有3个任务中最大的。你可以在下面的吐司消息截图中看到这一点
其他回答
启动返回一个作业
Async返回一个结果(延迟作业)
使用join启动用于等待作业完成。它只是挂起调用join()的协程,同时让当前线程空闲地做其他工作(比如执行另一个协程)。
Async用于计算一些结果。它创建一个协程,并将其未来结果作为Deferred的实现返回。当产生的延迟被取消时,正在运行的协程也被取消。
考虑一个返回字符串值的异步方法。如果async方法在没有await的情况下使用,它将返回一个Deferred字符串,但如果使用await,则将得到一个字符串作为结果
async和launch之间的关键区别: Deferred在协程完成执行后返回类型为T的特定值,而Job则不会。
除了其他很好的答案,对于熟悉Rx和进入协同程序的人来说,async返回一个类似于Single的Deferred,而launch返回一个更类似于Completable的Job。您可以.await()阻塞并获取第一个的值,.join()阻塞直到Job完成。
both coroutine builders namely launch and async are basically lambdas with receiver of type CoroutineScope which means their inner block is compiled as a suspend function, hence they both run in an asynchronous mode AND they both will execute their block sequentially. The difference between launch and async is that they enable two different possibilities. The launch builder returns a Job however the async function will return a Deferred object. You can use launch to execute a block that you don't expect any returned value from it i.e writing to a database or saving a file or processing something basically just called for its side effect. On the other hand async which return a Deferred as I stated previously returns a useful value from the execution of its block, an object that wraps your data, so you can use it for mainly its result but possibly for its side effect as well. N.B: you can strip the deferred and get its value using the function await, which will block the execution of your statements until a value is returned or an exceptions is thrown! You could achieve the same thing with launch by using the function join() both coroutine builder (launch and async) are cancelable. anything more?: yep with launch if an exception is thrown within its block, the coroutine is automatically canceled and the exceptions is delivered. On the other hand, if that happens with async the exception is not propagated further and should be caught/handled within the returned Deferred object. more on coroutines https://kotlinlang.org/docs/tutorials/coroutines/coroutines-basic-jvm.html https://www.codementor.io/blog/kotlin-coroutines-6n53p8cbn1
Launch和async用于启动新的协程。但是,他们以不同的方式来执行。
我想展示一个非常基本的例子,这将帮助你很容易地理解差异
发射
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btnCount.setOnClickListener {
pgBar.visibility = View.VISIBLE
CoroutineScope(Dispatchers.Main).launch {
val currentMillis = System.currentTimeMillis()
val retVal1 = downloadTask1()
val retVal2 = downloadTask2()
val retVal3 = downloadTask3()
Toast.makeText(applicationContext, "All tasks downloaded! ${retVal1}, ${retVal2}, ${retVal3} in ${(System.currentTimeMillis() - currentMillis)/1000} seconds", Toast.LENGTH_LONG).show();
pgBar.visibility = View.GONE
}
}
// Task 1 will take 5 seconds to complete download
private suspend fun downloadTask1() : String {
kotlinx.coroutines.delay(5000);
return "Complete";
}
// Task 1 will take 8 seconds to complete download
private suspend fun downloadTask2() : Int {
kotlinx.coroutines.delay(8000);
return 100;
}
// Task 1 will take 5 seconds to complete download
private suspend fun downloadTask3() : Float {
kotlinx.coroutines.delay(5000);
return 4.0f;
}
}
在这个例子中,我的代码下载3个数据点击btnCount按钮,并显示pgBar进度条,直到所有下载完成。有3个挂起函数downloadTask1(), downloadTask2()和downloadTask3()用于下载数据。为了模拟它,我在这些函数中使用了delay()。这些函数分别等待5秒,8秒和5秒。
因为我们已经使用launch来启动这些挂起函数,所以launch将依次执行它们(一个接一个)。这意味着,downloadTask2()将在downloadTask1()完成后启动,而downloadTask3()将仅在downloadTask2()完成后启动。
在输出截图Toast中,完成所有3个下载的总执行时间是5秒+ 8秒+ 5秒= 18秒
异步
正如我们所看到的,启动会依次执行所有3个任务。完成所有任务的时间是18秒。
如果这些任务是独立的,并且不需要其他任务的计算结果,我们可以让它们并行运行。它们将同时启动并在后台并发运行。这可以通过异步来完成。
async返回一个deferred <T>类型的实例,其中T是暂停函数返回的数据类型。例如,
downloadTask1()将返回Deferred<String>,因为String是函数的返回类型 downloadTask2()将返回Deferred<Int>,因为Int是函数的返回类型 downloadTask3()将返回Deferred<Float>,因为Float是函数的返回类型
我们可以使用类型为Deferred<T>的async的返回对象来获取T类型的返回值。这可以通过await()调用来完成。查看下面的示例代码
btnCount.setOnClickListener {
pgBar.visibility = View.VISIBLE
CoroutineScope(Dispatchers.Main).launch {
val currentMillis = System.currentTimeMillis()
val retVal1 = async(Dispatchers.IO) { downloadTask1() }
val retVal2 = async(Dispatchers.IO) { downloadTask2() }
val retVal3 = async(Dispatchers.IO) { downloadTask3() }
Toast.makeText(applicationContext, "All tasks downloaded! ${retVal1.await()}, ${retVal2.await()}, ${retVal3.await()} in ${(System.currentTimeMillis() - currentMillis)/1000} seconds", Toast.LENGTH_LONG).show();
pgBar.visibility = View.GONE
}
这样,我们就同时启动了所有3个任务。因此,我要完成的总执行时间只有8秒,这是downloadTask2()的时间,因为它是所有3个任务中最大的。你可以在下面的吐司消息截图中看到这一点
启动/异步没有结果
用在不需要结果的时候, 不要阻塞被调用的代码, 按顺序运行
Async for result
当需要等待结果时,可以并行运行 效率, 阻塞被调用的代码, 并发运行
推荐文章
- 如何使HTTP请求在PHP和不等待响应
- 反应-显示加载屏幕,而DOM是渲染?
- 如何正确地读取异步/等待文件?
- 使用Moq模拟单元测试的异步方法
- 如何在Kotlin延迟后调用函数?
- 如何使“不适当的阻塞方法调用”适当?
- Kotlin中的' forEach '中的' break '和' continue '
- 如何使用JUnit来测试异步进程
- Kotlin协程中的启动/连接和异步/等待之间有什么区别
- 在EditText Kotlin中设置文本
- Android 8.1升级后start前台失败
- 转换Kotlin数组到Java变量
- CompletableFuture, Future和RxJava的Observable之间的区别
- 挂起函数在Kotlin协程中意味着什么?
- 试图访问Kotlin片段中的视图时出现NullPointerException