`kotlinx.coroutines.withContext` 与 Spring WebFlux 一起使用是不是安全?

Posted

技术标签:

【中文标题】`kotlinx.coroutines.withContext` 与 Spring WebFlux 一起使用是不是安全?【英文标题】:Is `kotlinx.coroutines.withContext` safe to use with Spring WebFlux?`kotlinx.coroutines.withContext` 与 Spring WebFlux 一起使用是否安全? 【发布时间】:2021-09-05 05:16:46 【问题描述】:

想象一下,我有一个用 Kotlin 实现的 Spring WebFlux 控制器,看起来像这样:

@RestController
@RequestMapping("/api/foo")
class MyController 
  @GetMapping
  suspend fun getFoo(): FooResource 
    return withContext(Dispatchers.IO) 
      // fetch some resource with some expensive blocking IO call
    
  

我理解 WebFlux 的并发模型的方式,只有一个线程可以处理请求,所以如果我由于某种原因无法避免阻塞 IO 调用,我需要以某种方式将其卸载到另一个线程。 kotlinx.coroutines.withContext 助手应该就是这样做的,IO 调度程序是专门为这种用例设计的。`我在几篇博客文章中看到了这种模式,所以这似乎是常识

但是,[Dispatchers.IO 上的文档说:

此调度程序与默认调度程序共享线程,因此使用 withContext(Dispatchers.IO) ... 不会导致实际切换到另一个线程 - 通常在同一线程中继续执行。由于线程共享,在通过 IO 调度程序进行操作期间可以创建(但不使用)超过 64 个(默认并行度)线程。

所以这让我想知道:如果 WebFlux 只使用一个“主线程”来处理请求,并且即使我使用 withContext(Dispatchers.IO),阻塞 IO 仍然可能发生在这个线程中:这种模式可以安全使用吗?如果没有,我还应该怎么做?

【问题讨论】:

【参考方案1】:

是的,它是安全的,你正确理解了withContext

您在此处提到的那篇文档仅讨论了在IODefault 调度程序之间切换时对Dispatchers.IO 的优化(避免上下文切换)。

使用withContext(Dispatchers.IO) 来自除Default/IO 线程池之外的其他线程将正确(并且始终)将上下文切换到该 IO 线程池,根据需要启动新线程来处理阻塞 IO,所以这应该是在你的情况下要走的路。

【讨论】:

这让我放心了,谢谢!所以基本上这里的问题只是文档的措辞有点模棱两可。 我想主要的陈述很清楚,但是“所以使用 withContext(Dispatchers.IO) 不会导致......”这部分看起来确实太笼统了。它应该是“所以使用 withContext(Dispatchers.IO)当已经在 DIsptachers.Default 上运行时不会导致......”。 仅供参考,Kotlin 团队接受并合并 my PR 以澄清文档,所以这不再是问题了 :) 整洁!这就是承诺! :-)

以上是关于`kotlinx.coroutines.withContext` 与 Spring WebFlux 一起使用是不是安全?的主要内容,如果未能解决你的问题,请参考以下文章