协程(goroutines和kotlin协同程序)哪个更快?

时间:2017-10-21 15:01:40

标签: go kotlin coroutine goroutine kotlin-coroutines

Kotlin corutines是有限状态机的糖和一些任务运行器(例如,默认的ForkJoinPool)。 https://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-informal.md#implementation-details

换句话说,java / kotlin运行时中还没有运行时协程(但这可以随http://cr.openjdk.java.net/~rpressler/loom/Loom-Proposal.html而改变)。 Kotlin协程只是连续执行的任务,它们是逐个执行的。每个任务都可以在线程池的任何线程中执行。

Go运行时支持“协同程序”。但是goroutines并不是真正的协同程序。 Goroutines不允许在程序中设置屈服点。此外,Go不允许设置自定义线程池。您只能在默认池中设置线程大小。

kotlin协同程序和goroutines之间的第一个区别是Go运行时管理此时正在运行的协同程序。当goroutine在某些IO操作(或同步原语)被阻止时,请选择下一个Job来执行它。在JVM中,没有这种术语的智能工作转换。

因此,Go可以廉价地改变当前正在运行的工作。 Go只需更改少数注册管理机构 https://groups.google.com/forum/#!msg/golang-nuts/j51G7ieoKh4/wxNaKkFEfvcJ。但也有人说,JVM可以使用堆栈线程而不是使用寄存器。所以根本没有保存和加载寄存器。

kotlin协程和goroutines之间的第二个区别是协同程序的类型。 Kotlin协同程序是无堆栈协程。 Goroutines是堆栈协程。 Kotlin协程的所有状态都存储在Kotlin上下文中,该上下文存储在堆中。 Goroutines状态存储在寄存器和线程堆栈中。

我想知道,哪些协程(goroutines和kotlin协程)在IO绑定任务中更快? CPU绑定任务?内存消耗怎么样?

1 个答案:

答案 0 :(得分:52)

Kotlin中的协同程序以与Go中的goroutine不同的方式实现,因此哪一个更快"取决于您正在解决的问题以及您正在编写的代码类型。

一般来说,很难预先确定哪一个能够更好地解决您手头的问题。您必须为特定工作负载运行基准测试才能弄明白。但是,这里是关键差异的一般摘要,可以为您提供一些指导。

  • Kotlin协程每个简单实例比Go goroutines需要更少的内存。 Kotlin中的一个简单的协程只占用了几十个字节的堆内存,而Go goroutine则以4KiB的堆栈空间开始。这意味着,如果你计划拥有数以百万计的协同程序,那么Kotlin中的协同程序可能会比Go更具优势。它还使Kotlin协程更适合于非常短暂的小任务,如生成器和惰性序列。

  • Kotlin协程可以进入任何堆栈深度,但是每次调用suspending函数都会在堆中为堆栈分配对象。 Kotlin协同程序中的调用堆栈当前实现为堆对象的链接列表。相比之下,Go中的goroutines使用线性堆栈空间。这使得在深层堆栈上的挂起在Go中更有效。因此,如果您编写的代码在堆栈中非常深入,您可能会发现goroutine对您更有效。

  • 高效的异步IO是一个非常多维的设计问题。对于一种应用有效的方法可能无法为另一种应用提供最佳性能。 Kotlin协程中的所有IO操作都是用Kotlin或Java编写的库实现的。 Kotlin代码可以使用各种各样的IO库。在Go中,异步IO由Go运行时使用原始Go代码不可用的原语实现。如果Go实现IO操作的方法非常适合您的应用程序,那么您可能会发现它与Go运行时的紧密集成为您提供了优势。另一方面,在Kotlin中,您可以找到一个库,或者自己编写一个库,以最适合您应用的方式实现异步IO。

  • Go运行时完全控制在物理OS线程上调度goroutines执行。这种方法的优点是你不必考虑所有这些。使用Kotlin协程,您可以对协同程序的执行环境进行细粒度控制。这很容易出错(例如,您可能只是创建了太多不同的线程池,并且在它们之间的上下文切换上浪费了您的CPU时间)。但是,它使您能够为应用程序微调线程分配和上下文切换。例如,在Kotlin中,可以很容易地在单个OS线程(或线程池)中执行整个应用程序或其代码的子集,从而完全避免仅通过为此编写适当的代码来切换OS线程之间的上下文。