简体   繁体   English

在Task <T>完成之前,正确暂停协程的方法

[英]Correct way to suspend coroutine until Task<T> is complete

I've recently dove into Kotlin coroutines Since I use a lot of Google's libraries, most of the jobs is done inside Task class 我最近潜入Kotlin协同程序因为我使用了很多Google的库,所以大部分工作都是在Task类中完成的

Currently I'm using this extension to suspend coroutine 目前我正在使用此扩展来暂停协程

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!!)
        }
    }
}

But recently I've seen usage like this 但最近我见过这样的用法

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)
    }
}

Is there any difference, and which one is correct? 有什么区别,哪一个是正确的?

UPD: second example isn't working, idk why UPD:第二个例子不起作用,idk为什么

The block of code passed to suspendCoroutine { ... } should not block a thread that it is being invoked on, allowing the coroutine to be suspended. 传递给suspendCoroutine { ... }的代码块不应该阻塞正在调用它的线程,允许协程被挂起。 This way, the actual thread can be used for other tasks. 这样,实际线程可以用于其他任务。 This is a key feature that allows Kotlin coroutines to scale and to run multiple coroutines even on the single UI thread. 这是一个关键功能,允许Kotlin协程扩展并在单个UI线程上运行多个协同程序。

The first example does it correctly, because it invokes task.addOnCompleteListener (see docs) (which just adds a listener and returns immediately. That is why the first one works properly. 第一个例子是正确的,因为它调用task.addOnCompleteListener (参见docs) (它只是添加一个监听器并立即返回。这就是第一个正常工作的原因。

The second example uses Tasks.await(task) (see docs) which blocks the thread that it is being invoked on and does not return until the task is complete, so it does not allow coroutine to be properly suspended. 第二个示例使用Tasks.await(task) (请参阅docs)阻止调用它的线程,并且在任务完成之前不会返回,因此它不允许协程正确挂起。

Your second example is a more traditional Blocking function. 您的第二个示例是更传统的阻止功能。

In the world of typical Java multithreading, you use a function like that to block a thread until the result comes back. 在典型的Java多线程世界中,您使用类似的函数来阻塞线程,直到结果返回。

Also in typical Java, there is a newer paradigm called Reactive programming, which allows you to avoid blocking the thread until the result comes back. 同样在典型的Java中,有一种称为Reactive programming的新范例,它允许您在结果返回之前避免阻塞线程。 Instead of just waiting for the result, you supply a first-class function to be executed whenever the result arrives. 您可以提供一个在结果到达时执行的第一类函数,而不是仅仅等待结果。 That way, there isn't a thread left on pause; 这样,暂停时没有留下线程; instead, there's just a new event attached to the thread running the long operation, and when the operation is completed, that event will fire. 相反,只有一个新事件附加到运行长操作的线程上,当操作完成时,该事件将触发。

Blocking: 阻塞:

Thread one:  --* . . . ./---
Thread two:     \------*

Reactive: 反应:

Thread one: --*   (now free)
Thread two:    \-------*---

If you research Reactive Programming, you'll find much better explanations that go into a lot of depth. 如果你研究反应式编程,你会发现更好的解释,深入探讨。

Back to your question, though, these two ways of doing seemingly the same thing are a result of that paradigm shift from the Java world. 回到你的问题,这两种看似相同的方式是Java范式转变的结果。 Of course, since we're working with Coroutines here, we don't have to worry about that blocking problem at all ; 当然,由于我们与协程在这里工作,我们不必担心,阻断问题没有; the language takes care of it by suspending instead of blocking. 语言通过暂停而不是阻止来处理它。 So, a lot of the advantage of programming reactively is absolved on the langage level. 因此,反应性编程的许多优点在语言层面上得到了解决。

However , the paradigm still has its merits, so it would make sense to see people continuing to work in that pattern even when it's not as strictly necessary as elsewhere. 然而 ,范式仍然有其优点,所以即使它不像其他地方那样严格必要,看到人们继续以这种模式工作也是有道理的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM