我最近潜入Kotlin协程 由于我使用了很多Google的库,因此大部分工作都是在Task类
中完成的目前我正在使用此扩展来暂停协程
suspend fun <T> awaitTask(task: Task<T>): T = suspendCoroutine { continuation ->
task.addOnCompleteListener { task ->
if (task.isSuccessful) {
continuation.resume(task.result)
} else {
continuation.resumeWithException(task.exception!!)
}
}
}
但是最近我看到了这样的用法
suspend fun <T> awaitTask(task: Task<T>): T = suspendCoroutine { continuation ->
try {
val result = Tasks.await(task)
continuation.resume(result)
} catch (e: Exception) {
continuation.resumeWithException(e)
}
}
有什么区别,哪一个是正确的?
UPD:第二个例子不起作用,idk为什么
答案 0 :(得分:10)
传递给suspendCoroutine { ... }
的代码块不应该阻塞正在调用它的线程,允许协程被挂起。这样,实际线程可以用于其他任务。这是一个关键功能,允许Kotlin协程扩展并在单个UI线程上运行多个协同程序。
第一个示例正确执行,因为它调用task.addOnCompleteListener
(see docs)(它只是添加一个侦听器并立即返回。这就是第一个正常工作的原因。
第二个示例使用Tasks.await(task)
(see docs) 阻止调用它的线程,并且在任务完成之前不会返回,因此它不允许协程正确挂起。
答案 1 :(得分:1)
您的第二个示例是更传统的阻止功能。
在典型的Java多线程世界中,您使用类似的函数来阻塞线程,直到结果返回。
同样在典型的Java中,有一种称为反应式编程的新范例,它允许您在结果返回之前避免阻塞线程。您可以提供一个在结果到达时执行的第一类函数,而不是仅仅等待结果。这样,暂停时没有留下线程;相反,只有一个新事件附加到运行长操作的线程上,当操作完成时,该事件将触发。
封闭:
Thread one: --* . . . ./---
Thread two: \------*
活性:
Thread one: --* (now free)
Thread two: \-------*---
如果你研究反应式编程,你会发现很多深入的解释。
回到你的问题,这两种看似相同的方式是Java范式转变的结果。当然,既然我们在这里与Coroutines合作,我们就不必担心的阻塞问题;该语言通过暂停而不是阻止来处理它。因此,反应性编程的许多优点都可以在语言层面上得到解决。
然而,这种范式仍然有其优点,所以即使它不像其他地方那样严格必要,看到人们继续以这种模式工作也是有道理的。