为什么 kotlin 协程被称为异步?

Fox*_*Net 5 java multithreading asynchronous kotlin

Jetbrains 在每一篇有关 kotlin 的文章中都谈到了异步编程。但我不明白为什么它们被称为异步?据我了解 kotlin 协程 - 这是一个带有预初始化线程池的状态机。我们有一个工作线程池和一个io线程池。对我来说这只是多线程编程。如果我们向协程发送阻塞代码,则线程将被阻塞。如果我们使用异步方法(来自默认协程库),它会给我们一种异步工作的错觉,但这只不过是将“作业”发送到另一个线程。

如果我们将 async io 与协程一起使用,另一个问题是。但这是 IO API 异步,而不是 kotlin 协程。与其他语言相比,Java 的 io 异步 api 并不好(可能是错误的)。据我所知,.NET 已经重建了他们的异步 api(如 IOCP)以使用 C# 任务,并且 .NET 有专用的线程池来等待应用程序的所有 IO,因此一个线程可以处理许多 IO 操作。但是 kotlin 协程没有集成到 java nio 中,当我们从协程(带或不带 Dispatcher.IO)调用 nio 时,我们只是要求线程等待来自 nio 的数据。Java NIO 有自己的 epoll 或 iocp 线程池,因此使用 kotlin 协程,当我们要求 Dispatcher.IO 为我们提供一个等待 NIO 结果的线程时,我们会产生开销,之后 NIO 实现会创建自己的线程(池)来等待数据从插座。我们现在有两个线程(池),而不是一个等待线程(池)。

因此,协程允许我们以简单的方式将作业发送到另一个线程。如果您的 api 未使用 kotlin 协程以异步方式实现,则您无法同时使用一个线程执行多项操作。

mig*_*WOZ 1

他们谈论异步编程是因为协程主要(但不限于)作为库出售,以使异步编程更容易(主观)。但正如您正确指出的那样,协程本身没有任何异步之处。如果您在协程中执行阻塞代码,它将阻塞底层线程。

但要理解的一点是,协程只有在与挂起函数结合使用时才真正有利,其中线程除了等待结果(回调)之外什么都不做。因此,您可以使用同一个线程再执行十次这样的调用,而不是等待。另一个主要优点是使用协程编写的异步代码更容易编写和维护。例如,以下是使用回调的异步调用

fun callAPI(){
    getToken{ token ->
        auth(token){ authResult ->
            doSomething(authResult){ finalResult ->
               // use final result
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这可以简化为使用协程和挂起函数

fun callAPI() = scope.launch(){
    val token = getToken()
    val authResult = auth(token)
    val finalResult = doSomething(authResult)
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以使用协程来启动多个长时间运行的阻塞任务,但您不会看到任何优势。因为在这种情况下,协程只不过是线程之上无用的抽象。