【问题标题】:Suspending IO-bound and CPU-bound functions in Kotlin's coroutines在 Kotlin 的协程中暂停 IO-bound 和 CPU-bound 函数
【发布时间】:2019-09-24 08:28:35
【问题描述】:

在协程中执行一个 IO 绑定函数(例如,从后端请求数据)给了我一个优势,即在请求结果可用之前暂停它的执行,对吧?但是,受 CPU 限制的函数(例如,解析一个巨大的文本文件)不会“等待”任何东西,它只是做了很多工作。那么,在协程中执行它不会给我暂停执行的优势吗?当涉及到受 CPU 限制的函数时,协程给我的唯一(有价值的)优势是能够选择在执行函数时将被阻塞的线程(或线程池),对吗?

【问题讨论】:

    标签: kotlin kotlin-coroutines


    【解决方案1】:

    那么,在协程中执行它不会给我暂停执行的优势吗?

    我不确定我理解你的意思,但是调用挂起函数无论如何都会挂起调用协程,无论你选择什么调度程序,据我所知,这并不取决于函数内部的内容。

    但是,请注意,从协程内部调用一个阻塞函数会使这个协程阻塞执行它的线程,这里没有魔法。这就是为什么在协程中应该避免阻塞操作。

    协程在 CPU 绑定函数方面给我的唯一(有价值的)优势是能够选择在执行函数时将被阻塞的线程(或线程池),对吗?

    使用Dispachers.IODispatchers.Default 仅具有选择不同线程池的效果,是的。

    IO 的情况下,池将根据需要生成尽可能多的线程,因为它们都可以“在 I/O 上被阻塞”。

    Default 的情况下,只会创建与内核数量成比例的线程数,因为 CPU-bound 任务创建的线程数比内核数多(如果所有内核都忙) ,那么上下文切换只会降低整体性能)。

    【讨论】:

    • 我的协程心智模型仍然很混乱,对不起,@Joffrey。如果我只是在 CPU 绑定函数的声明中写上“暂停”并在 launch(Dispatchers.Unconfined) 中调用它,我会得到什么好处?它与对 IO 绑定函数执行相同操作有什么不同吗?
    • @bernardo.g 我不是Unconfined 调度程序的专家,但除非您有非常具体的用例,否则不鼓励这样做。 AFAIU,它使协程在当前线程中启动,直到第一个挂起点,然后根据调用的挂起函数在可能不同的线程中恢复。这意味着您的协程的开头保证会立即执行。
    • @bernardo.g 但是,如果你做的第一件事是调用你的 CPU 绑定的挂起函数,这是一个挂起点,我想你的函数很可能在另一个线程中执行,但是我知道的不够多,无法确定。因此,IMO,我认为执行您在此处描述的操作没有任何“优势”,并且我认为使用 IO 绑定函数执行此操作没有区别,除了 IO 绑定函数可能阻塞它被调用的线程。
    【解决方案2】:

    挂起函数不会自动使函数不阻塞线程,就像在下面的情况下,它仍然会阻塞调用线程(调度程序与用于启动协程的作用域相关联)

    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

    【讨论】:

      猜你喜欢
      • 2022-01-10
      • 1970-01-01
      • 2016-03-21
      • 1970-01-01
      • 2018-07-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多