【发布时间】:2019-09-24 08:28:35
【问题描述】:
在协程中执行一个 IO 绑定函数(例如,从后端请求数据)给了我一个优势,即在请求结果可用之前暂停它的执行,对吧?但是,受 CPU 限制的函数(例如,解析一个巨大的文本文件)不会“等待”任何东西,它只是做了很多工作。那么,在协程中执行它不会给我暂停执行的优势吗?当涉及到受 CPU 限制的函数时,协程给我的唯一(有价值的)优势是能够选择在执行函数时将被阻塞的线程(或线程池),对吗?
【问题讨论】:
在协程中执行一个 IO 绑定函数(例如,从后端请求数据)给了我一个优势,即在请求结果可用之前暂停它的执行,对吧?但是,受 CPU 限制的函数(例如,解析一个巨大的文本文件)不会“等待”任何东西,它只是做了很多工作。那么,在协程中执行它不会给我暂停执行的优势吗?当涉及到受 CPU 限制的函数时,协程给我的唯一(有价值的)优势是能够选择在执行函数时将被阻塞的线程(或线程池),对吗?
【问题讨论】:
那么,在协程中执行它不会给我暂停执行的优势吗?
我不确定我理解你的意思,但是调用挂起函数无论如何都会挂起调用协程,无论你选择什么调度程序,据我所知,这并不取决于函数内部的内容。
但是,请注意,从协程内部调用一个阻塞函数会使这个协程阻塞执行它的线程,这里没有魔法。这就是为什么在协程中应该避免阻塞操作。
协程在 CPU 绑定函数方面给我的唯一(有价值的)优势是能够选择在执行函数时将被阻塞的线程(或线程池),对吗?
使用Dispachers.IO 或Dispatchers.Default 仅具有选择不同线程池的效果,是的。
在IO 的情况下,池将根据需要生成尽可能多的线程,因为它们都可以“在 I/O 上被阻塞”。
在Default 的情况下,只会创建与内核数量成比例的线程数,因为 CPU-bound 任务创建的线程数比内核数多(如果所有内核都忙) ,那么上下文切换只会降低整体性能)。
【讨论】:
launch(Dispatchers.Unconfined) 中调用它,我会得到什么好处?它与对 IO 绑定函数执行相同操作有什么不同吗?
Unconfined 调度程序的专家,但除非您有非常具体的用例,否则不鼓励这样做。 AFAIU,它使协程在当前线程中启动,直到第一个挂起点,然后根据调用的挂起函数在可能不同的线程中恢复。这意味着您的协程的开头保证会立即执行。
挂起函数不会自动使函数不阻塞线程,就像在下面的情况下,它仍然会阻塞调用线程(调度程序与用于启动协程的作用域相关联)
suspend fun findBigPrime(): BigInteger =
BigInteger.probablePrime(4096, Random())
可以通过使用 withContext 将挂起函数变成非阻塞线程函数,如下所示,
suspend fun findBigPrime(): BigInteger =
withContext(Dispatchers.Default) {
BigInteger.probablePrime(4096, Random())
}
这会导致从主/调用者线程启动的协程阻塞,但线程本身不会阻塞。
https://medium.com/@elizarov/blocking-threads-suspending-coroutines-d33e11bf4761
【讨论】: