在kotlinx。协程库,您可以使用启动(使用join)或异步(使用await)启动新的协程。它们之间的区别是什么?
当前回答
启动返回一个作业
Async返回一个结果(延迟作业)
使用join启动用于等待作业完成。它只是挂起调用join()的协程,同时让当前线程空闲地做其他工作(比如执行另一个协程)。
Async用于计算一些结果。它创建一个协程,并将其未来结果作为Deferred的实现返回。当产生的延迟被取消时,正在运行的协程也被取消。
考虑一个返回字符串值的异步方法。如果async方法在没有await的情况下使用,它将返回一个Deferred字符串,但如果使用await,则将得到一个字符串作为结果
async和launch之间的关键区别: Deferred在协程完成执行后返回类型为T的特定值,而Job则不会。
其他回答
Async和Launch,两者都用于创建在后台运行的协程。几乎在任何情况下,人们都可以使用它们中的任何一个。
tl;博士版:
当你不关心任务的返回值,只想运行它时,你可以使用Launch。如果你需要任务/协程的返回类型,你应该使用async。
Alternate: However, I feel the above difference/approach is a consequence of thinking in terms of Java/one thread per request model. Coroutines are so inexpensive, that if you want to do something from the return value of some task/coroutine(lets say a service call) you are better off creating a new coroutine from that one. If you want a coroutine to wait for another coroutine to transfer some data, I would recommend using channels and not the return value from Deferred object. Using channels and creating as much number of coroutines as required, is the better way IMO
详细的回答:
唯一的区别是返回类型和它提供的功能。
Launch返回Job, Async返回Deferred。有趣的是,Deferred扩展了Job。这意味着它必须在Job之上提供额外的功能。Deferred是在T是返回类型的地方参数化的类型。因此,Deferred对象可以从async方法执行的代码块中返回一些响应。
附注:我之所以写下这个答案,是因为我在这个问题上看到了一些事实上不正确的答案,我想为大家澄清这个概念。另外,在我自己做一个宠物项目时,由于之前有Java背景,我也遇到过类似的问题。
除了其他很好的答案,对于熟悉Rx和进入协同程序的人来说,async返回一个类似于Single的Deferred,而launch返回一个更类似于Completable的Job。您可以.await()阻塞并获取第一个的值,.join()阻塞直到Job完成。
启动返回一个作业
Async返回一个结果(延迟作业)
使用join启动用于等待作业完成。它只是挂起调用join()的协程,同时让当前线程空闲地做其他工作(比如执行另一个协程)。
Async用于计算一些结果。它创建一个协程,并将其未来结果作为Deferred的实现返回。当产生的延迟被取消时,正在运行的协程也被取消。
考虑一个返回字符串值的异步方法。如果async方法在没有await的情况下使用,它将返回一个Deferred字符串,但如果使用await,则将得到一个字符串作为结果
async和launch之间的关键区别: Deferred在协程完成执行后返回类型为T的特定值,而Job则不会。
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
当需要等待结果时,可以并行运行 效率, 阻塞被调用的代码, 并发运行
推荐文章
- Kotlin中惯用的登录方式
- 如何在Kotlin中实现生成器模式?
- 同步和异步编程(在node.js中)的区别是什么?
- Kotlin中的单个感叹号
- 如何允许所有网络连接类型HTTP和HTTPS在Android(9)馅饼?
- 如何克隆或复制一个列表在kotlin
- 如何将字符串转换为长在Kotlin?
- 如何在Kotlin解析JSON ?
- 什么Java 8流。收集等价物可在标准Kotlin库?
- 等待一个无效的异步方法
- 使用Python请求的异步请求
- PHP中的异步shell执行器
- Python中的异步方法调用?
- Android房间-简单的选择查询-不能访问数据库在主线程
- 如何检查“instanceof”类在kotlin?