当您开始学习Kotlin协程时,您看到的第一个示例之一是可以启动数十万个协程,但在尝试对线程执行相同的操作时会遇到OutOfMemory异常。
虽然这个例子很“酷”,但我不认为它对现实世界的Android应用程序开发有什么用处,甚至有点误导。当然,您可以启动数十万个只做delay()的协程,但在现实中,您要么启动执行某种IO或某种计算的协程。
例如,如果您启动了数十万个协程,并且每个协程都使用Retrofit执行一个网络请求,那么它不会比传统地使用没有协程的Retrofit更轻量级,因为okhttp仍然会为每个请求阻塞一个线程。
当您使用协程进行计算时,情况也是如此。那么它也不是更轻量级的,因为执行计算的线程会被阻塞,直到它们完成。
那么,我的假设是正确的吗?如果没有非阻塞IO库的存在,我的应用程序不会因为使用协程而变得更高效或更“轻量级”,还是我错过了什么?
发布于 2020-05-07 19:08:27
当然,您可以启动数十万个只做
()的协程,但实际上,您要么启动执行某种IO或某种计算的协程。
不一定。协程对于重新组织其他类型的代码也很有用,比如working with views。
例如,如果你启动了成百上千的协程,并且每个协程都执行了一个带有
的网络请求,那么它不会比没有协程的传统的Retrofit更轻量级,因为okhttp仍然会为每个请求阻塞一个线程。
我猜你是想说OkHttp使用了一个线程池。这绝对是事实。
当你在协程中进行计算时,
也是如此。那么它也不是更轻量级的,因为执行计算的线程会被阻塞,直到它们完成。
这是您原始段落中的OutOfMemoryError场景,如果您每次计算都要创建单独的线程。
协程调度程序是基于线程池的。“成百上千的协程”场景最终将不使用线程池与使用线程池进行了比较。所以,是的,“几十万个协程”的比较并不显著,因为还有其他使用线程池的方式。
发布于 2020-05-07 19:22:45
您部分正确,打开多个阻塞IO请求将排队到Dispatchers.IO中,如果最大请求数超过64 ( IO Dispatcher上的最大线程数),它们将按顺序执行,即随着线程将被释放而逐个执行。
协程并不神奇,它们只是通过一个在幕后充当回调处理程序的Continuation将回调转换成看起来像是连续的代码。
现实应用程序中的协程通常受益于更改线程、冷流、通道的简单性,从而挂起的协程接收值在恢复之前不会实质上占用线程。
虽然RxJava做了同样的事情,但协同例程的基准测试表明,它消耗的内存更少,完成check benchmarks here所需的时间也明显更少。
您还可以使用协程通过使用堆内存而不是堆栈来实际实现深度递归,请参阅Roman's elizarov implementation of deep recursion using the coroutines它们是否足够轻量级?
https://stackoverflow.com/questions/61654349
复制相似问题