Joe*_*Dow 6 multithreading kotlin kotlin-coroutines
如果协程仍然使用线程并行运行代码,为什么它被认为是轻量级的?
在我的理解 kotlin 的suspend
功能被编译器转换成状态机,其中每个分支可以在开发人员定义的相同或不同线程上运行。协程构建器,例如,launch{}
负责它并CoroutineContext
定义要运行的线程。
通过将代码块发送到利用相同线程的线程池来实现并行性
有一个关于 100k 协程和 100k 线程的基准测试,其中协程毫无问题地通过并且线程抛出异常(可能是 OutOfMemory)。这让我想到我在这里遗漏了一些东西。
你能帮我理解这里遗漏了什么,是什么让协程并行运行代码块 100k 而不像线程那样超过内存限制?
从文章中指点
每个
Thread
都有自己的堆栈,通常为 1MB。64k 是 JVM 中每个线程允许的最小堆栈空间量,而 Kotlin 中的简单协程仅占用几十字节的堆内存。
Coroutine Dispatcher 有一个限制,即只能创建一定数量的线程。
例如Dispatchers.IO限制为 64 个线程,Dispatchers.Default限制处理器上的核心数(2、4、6、8 等)Dispatchers.Unconfined无法创建新线程,它在其他人先前创建的线程上运行调度员,这里有证据:500 次操作有 10 毫秒的睡眠时间大约需要 5 秒(单线程,因为它不能产生一个新线程)自己尝试一下。
协程粘在一个线程上,一旦到达暂停点,它就会离开线程并释放它,让它在等待时接收另一个协程。这种方式使用更少的线程和更少的内存,可以完成大量的并发工作。
协程由类似回调的对象管理挂起和恢复,该对象Continuation
作为最后一个参数添加到suspend
编译时用关键字标记的函数中,该函数像其他对象一样存在于堆中并负责协程的恢复,所以RAM 中不需要数千 MB 的空间来保持所有线程处于活动状态。一个典型的 60-70 个线程在 max using 下创建CommonPool
并被重用(如果创建了新的协程,它会等待另一个完成)。
主要的节省来自这样一个事实:单个线程可以通过协作多任务处理来运行任意数量的协程。当您启动 100,000 个协程时,它们会在与 CPU 核心数量一样多的线程上运行,但是当您启动 100,000 个线程时,JVM 会创建同样多的本机线程。请注意,两种情况下的并行级别相同,并且受限于 CPU 核心的数量。
唯一改变的是调度:在经典情况下,操作系统挂起和恢复线程,将它们分配给 CPU 核心。对于协程,协程会暂停自身(这是它们的合作方面),并Dispatcher
稍后恢复它们,同时运行其他协程。
归档时间: |
|
查看次数: |
895 次 |
最近记录: |