Kotlin中关于协程的一个关键概念是suspend函数必须从协程或另一个suspend函数调用。但是,suspend函数可以调用任何类型的函数,suspend或normal。那会有什么后果?(这不是我拥有的真实的场景,只是出于理论原因想知道)我想在那种情况下,创建协程的唯一目的就是在调用它之前改变上下文(线程),这样它就不会阻塞主线程。然而,协程的所有其他优点会失去吗?(合作取消,结构化并发...)
dpiehjr41#
如果一个挂起的函数调用另一个挂起的函数,那么协程将被挂起,直到返回结果。从一个挂起的函数调用一个常规函数会阻塞线程。哪个线程?嗯,这取决于你使用的调度器。IO能够产生数百个线程。但是Default调度器的线程数量与你的CPU数量相同。这意味着虽然这不会阻塞其他协程,但会减少可用资源的数量。含义:不要调用非挂起函数,因为它可能会在这个调度器上阻塞很长一段时间,就像不要阻塞UI线程一样。是的,挂起函数可能会产生相同的结果,如果你正在做一个没有yield()或任何其他挂起调用的忙碌循环。
IO
Default
UI
yield()
iezvtpos2#
挂起函数可以在中间挂起,稍后再继续。从挂起函数调用普通函数将失去暂停执行的能力。当一个挂起函数被编译时,Kotlin编译器在参数中加入一个延续对象作为参数。这个延续对象是挂起一个协同程序所需要的。当一个挂起函数调用另一个挂起函数时,它传递这个延续对象,这与协同程序一样。如果一个非挂起函数被挂起函数调用,你就不能使用那个函数的协同例程了......就是这样
sh7euo9m3#
然而,协程的所有其他优点会丧失吗?(协作取消、结构化并发......)即使是不可挂起的函数也可以通过显式地检查CoroutineContext.isActive标志来参与协作取消,尽管这更多的是一个理论上的事实。如果一个函数执行了一个阻塞IO操作,它将不会响应取消请求。该操作必须自己完成。至于结构化并发,与您所关心的几乎相反:Kotlin的最佳实践是从一个 non-suspendable 函数启动子协程,而这个函数是CoroutineScope上的一个扩展,并调用协程构建器,将它作为接收器。
CoroutineContext.isActive
CoroutineScope
3条答案
按热度按时间dpiehjr41#
如果一个挂起的函数调用另一个挂起的函数,那么协程将被挂起,直到返回结果。
从一个挂起的函数调用一个常规函数会阻塞线程。哪个线程?嗯,这取决于你使用的调度器。
IO
能够产生数百个线程。但是Default
调度器的线程数量与你的CPU数量相同。这意味着虽然这不会阻塞其他协程,但会减少可用资源的数量。含义:不要调用非挂起函数,因为它可能会在这个调度器上阻塞很长一段时间,就像不要阻塞
UI
线程一样。是的,挂起函数可能会产生相同的结果,如果你正在做一个没有
yield()
或任何其他挂起调用的忙碌循环。iezvtpos2#
挂起函数可以在中间挂起,稍后再继续。从挂起函数调用普通函数将失去暂停执行的能力。
当一个挂起函数被编译时,Kotlin编译器在参数中加入一个延续对象作为参数。这个延续对象是挂起一个协同程序所需要的。当一个挂起函数调用另一个挂起函数时,它传递这个延续对象,这与协同程序一样。
如果一个非挂起函数被挂起函数调用,你就不能使用那个函数的协同例程了......就是这样
sh7euo9m3#
然而,协程的所有其他优点会丧失吗?(协作取消、结构化并发......)
即使是不可挂起的函数也可以通过显式地检查
CoroutineContext.isActive
标志来参与协作取消,尽管这更多的是一个理论上的事实。如果一个函数执行了一个阻塞IO操作,它将不会响应取消请求。该操作必须自己完成。
至于结构化并发,与您所关心的几乎相反:Kotlin的最佳实践是从一个 non-suspendable 函数启动子协程,而这个函数是
CoroutineScope
上的一个扩展,并调用协程构建器,将它作为接收器。