Kotlin Coroutine 相当于 Spring Java 中的 @Async

问题描述 投票:0回答:1

Spring提供了一种支持异步执行的方式,注解

@Async
@EnableAsync
,在下面的Java代码中,我的API不会被阻塞并且可以响应而无需等待昂贵的操作完成。

@Post
public Response saveUserDetail(UserDetail userDetail) {
   System.out.println("saveUserDetail Started...");
   // very expensive operation
   userRepo.save(userDetail);
   System.out.println("saveUserDetail Completed...");
}

@Async
public void save(UserDetail userDetail) {
   // took 30s
   Thread.sleep(30000);
}

现在 Kotlin 有一个协程包来以同步方式编写异步过程,但是,如果不使用

@Async
,Kotlin 实现上述行为的方法是什么?我试过
suspend
async
但他们似乎仍然会阻止我的请求线程,如果不等待昂贵的操作我就无法获得我的 API 响应

spring kotlin asynchronous kotlin-coroutines
1个回答
1
投票

Kotlin 协程与常规 Java 线程不同。协程有两个不同于线程的属性,我认为这两个属性与你相关:

  1. 协程使用结构化并发。在所有子协程完成之前,外部协程范围不会完成。

  2. 协程不应被

    Thread.sleep()
    等调用阻塞,除非注意在为其设计的调度程序中运行此类阻塞代码,例如
    Dispatchers.IO
    。相反,使用像
    delay()
    这样的挂起调用,有关详细信息,请参阅https://stackoverflow.com/a/76009163/430128

现在在您的情况下,您似乎希望

saveUserDetail
完成而不等待
save
完成。请记住,这段 Spring 代码并不安全,因为如果
saveUserDetail
抛出错误,客户端永远不会知道。或者,如果
saveUserDetail
由于某种原因永远不会返回,则线程将泄漏。 Kotlin 中的结构化并发旨在默认防止此类不安全代码。使用协程和结构化并发,直到
saveUserDetail
调用完成才会返回响应,并且是否使用
async
launch
协程构建器并不重要,因为默认情况下它们只是启动子协程.父母仍然不会完成,直到由
async
launch
开始的子协程完成。

如果您真的想要此代码的不安全版本,则需要将协程启动到另一个协程范围,该范围不是请求范围的子级,例如

GlobalScope
。例如:

GlobalScope.launch {
  userRepo.save(userDetail);
}

确保您阅读了文档中使用

GlobalScope
的所有注意事项。

您还可以创建自己的后台范围并使用它。例子:

val backgroundOpsScope = CoroutineScope(SupervisorJob())
...
suspend fun saveUserDetail(userDetail: UserDetail): Response {
  backgroundOpsScope.launch {
    ... expensive operation ...
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.