挂起功能在单独的线程上运行? 如果没有,那么性能收益是什么?
suspend fun requestToken():Token {..} // takes 2 sec to complete
suspend fun createPost (token:Token){..} // takes 3 sec to complete
suspend fun postItem() {
val token = requestToken()
val post =createPost(token)
processPost(post)
}
因此,当我们到达 processPost(post)时,如果未在单独的线程上运行suspend函数,则我们必须等待 requestToken()和 createPost(令牌)方法 完成(即2 + 3 = 5秒)。根据作者的说法,暂停是异步的,但是如果我们不产生任何新线程,那么我们如何实现异步行为呢?
答案 0 :(得分:4)
暂停是异步的
ng-class="{active: $index == selected}"
与调用者同步执行。您实际上要说的是“无障碍”,这是一个完全不同的故事。
但是如果我们不产生任何新线程,那么我们如何实现异步行为?
您默认所有I / O必须在某个级别进行阻塞。错了非阻塞I / O的工作原理是将数据推送到发送缓冲区,并在接收缓冲区中有数据时接收通知。 suspend fun
通过在将数据推送到发送缓冲区后挂起自身并安装回调程序(该回调程序将在接收缓冲区中的响应数据准备就绪时将其恢复)来挂起该机制。
答案 1 :(得分:1)
悬浮点只能在协程环境中使用,例如:
fun main() {
delay(1000)
}
将不起作用,因为delay
是一个暂停函数,编译器将不知道如何在没有协程的情况下处理该问题。当您拥有协程时,它可以使用一种称为调度程序的东西来控制线程所有权。挂起意味着该线程不再用于执行程序的那部分,而是执行其他操作或变为空闲状态。它的工作方式是,您可以同时运行多个协程,而不必每个线程都有一个线程,然后该线程可以执行每个协程的各个部分,直到一个挂起点。通常的想法是,您可以将挂起函数视为“生成器”,它们具有产生结果的阶段。
suspend fun hello() {
println("Hello")
delay(1000) // suspend here, let someone else use the thread while we wait
println("World")
delay(1000) // suspend again, we can still use the thread while waiting
println("done")
}
每次被暂停时,它都会使用该线程来执行另一个函数,直到该函数暂停并且延迟到期为止,届时该函数将最终继续执行直到下一个暂停点或完全完成执行
这与阻塞代码不同,因为阻塞代码不会通过将线程置于 wait 状态而浪费线程,而是将其借用到另一个函数。这样一来,无需创建其他线程即可具有并发性,因为您仍然可以在没有真正的并行性的情况下使用多个函数,而使用并发执行部分函数。
协同程序并不一定能保护您免受阻塞,如果您呼叫Thread.sleep(1000)
,它仍然会成为阻塞呼叫。程序员有责任使用暂停等效项来阻塞函数,以最大限度地提高此概念的有效性。
有关更多详细信息,请阅读documentation,因为它非常详细且很有帮助。
答案 2 :(得分:-1)
可以显式声明线程池的背景单线程或多个后台线程,然后使用它,例如,通过将其作为参数传递,我们将此参数称为“调度程序”。真正有趣的是,它最初是从主线程启动的,然后自动切换到调度程序线程以在其上执行特定任务,并且虚拟机在此位置被挂起或中断,而主线程变得更凉爽的事情不受阻碍,并且可以在后台执行任务时执行其他操作。
任务完成后,虚拟机将立即返回到之前已被挂起或中断的位置,然后从该点恢复执行,但现在也从虚拟机的后台线程返回了结果。调度程序,下面是代码片段:
private val backgroundThread = ThreadPoolExecutor(1, 1, 15L, TimeUnit.SECONDS, LinkedBlockingQueue())
GlobalScope.launch(Dispatchers.Main, CoroutineStart.DEFAULT) {
postItem(backgroundThread))
}
suspend fun CoroutineScope.postItem(scheduler: ThreadPoolExecutor): Boolean {
val token = requestToken(scheduler)
val post = createPost(token, scheduler)
return processPost(post, scheduler)
}
private suspend fun CoroutineScope.requestToken(scheduler: ThreadPoolExecutor): String {
val def: Deferred<String?> = async(scheduler.asCoroutineDispatcher(), CoroutineStart.DEFAULT) {
val token = networkApi.requestToken()
}
return def.await() ?: ""
}
private suspend fun CoroutineScope.createPost(token: String, scheduler: ThreadPoolExecutor): String {
val def: Deferred<String?> = async(scheduler.asCoroutineDispatcher(), CoroutineStart.DEFAULT) {
val post = networkApi.createPost(token)
}
return def.await() ?: ""
}
private suspend fun CoroutineScope.processPost(post: String, scheduler: ThreadPoolExecutor): Boolean {
val def: Deferred<Boolean?> = async(scheduler.asCoroutineDispatcher(), CoroutineStart.DEFAULT) {
val result = networkApi.processPost(post)
}
return def.await() ?: false
}