什么时候使用 Kotlin suspend 关键字?

When to use Kotlin suspend keyword?

fun startAsyncFunc() {
  launch {
    asyncFunc1()
    asyncFunc2()
  }
}

fun asyncFunc1() { ... }
suspend fun asyncFunc2() { ... }

不用suspend我也能完成工作,而且测试更简单(不用加runBlocking.

也能测试

我的问题:

  1. asyncFunc1 vs asyncFunc2,哪个更好,为什么?
  2. 如果 asyncFunc2 更好,我是否应该在协程中的函数为 运行 时始终使用 suspend

更新

在最近发布的 Kotlin Coroutines 中,我注意到如果一个方法不包含任何协程代码(如 launchasync 等),编译器会报错 This inspection reports a suspend modifier as redundant if no other suspend functions are called inside .所以我认为 suspend 应该只在必须的时候使用。

更新2

An advice from Google

来自docs

Suspending functions can be used inside coroutines just like regular functions, but their additional feature is that they can, in turn, use other suspending functions, like delay in this example, to suspend execution of a coroutine.

suspend 关键字表示协程可以挂起以便稍后执行。

话虽如此,您应该有意识地将它们用于将被挂起的协程(e.q。您的 asyncFunc2() 进行了 HTTP 调用并正在等待响应以处理它)

所以。

  1. suspend用于将以某种方式延迟的函数(等待某些计算、api响应等)
  2. suspend fun 只能来自协程 运行。因此,如果它被挂起,它将阻塞协程。去掉suspend关键字,但是在协程中运行,效果是一样的。但是,如果您从协程外部 运行 此函数,它将阻塞它 运行 正在运行的线程。

测试协程时,您应该始终调用 runBlocking。否则,挂起的协程可能无法完成,从而导致测试失败。

  1. 视情况而定。此时看到其他两个答案的组合:从协程中调用任一函数的效果是相同的。但是,通过 suspend 关键字,函数本身可以调用其他挂起函数。使用关键字可能表示某些工作需要时间,因此可能需要暂停调用协程。
  2. 总是从协程调用的函数不需要总是有 suspend 关键字。由于第 1 条给出的原因,它只需要该关键字。反之亦然:挂起函数只能从协同程序中调用。

您应该只在需要时才声明您的函数 suspend。我会说,如果有疑问,如果编译器不强制你,不要使用 suspend.

大多数时候,如果你有充分的理由让你的函数挂起,这意味着它正在做一些可能需要你调用挂起函数的事情,比如 withContext 无论如何,或者它可能是一个回调通过 suspendCoroutine/suspendCancellableCoroutine 公开为暂停的基于函数。无论哪种方式调用这些函数都会迫使您声明自己的函数 suspend.

请注意,声明一个函数 suspend 并不能使您的调用者比您的函数未挂起时做更多的事情。如果有的话,你限制了你的功能的使用。

如果您将此函数定义为开放方法(例如在接口中)并且您希望某些 implementations/overrides 需要自己调用挂起函数。

将 suspend 关键字用于:

  • 将以某种方式延迟的功能(等待一些计算、网络请求)

    • 每当函数调用其他挂起函数时
    • 调用 withContext() 的函数 – withContext() 是一个来自协程库的挂起函数

经验法则是不要将函数标记为挂起,除非你被迫这样做