当前位置: 首页 > 知识库问答 >
问题:

如果只进行一次同步调用,Webflux会发生什么?

严斌
2023-03-14

我开始在Spring Boot中使用Webflux进行反应式Java编程。

我遇到了一个场景,很难被动地执行某个数据库调用。

如果我在Mono中执行单个阻塞数据库调用,会发生什么?

代码看起来像这样。。。

public Mono<ReturnThing> isThisAsyncOrNot() {
    //Async, non-blocking API call
    return webClient.doSomeAPIWork()
                     .flatMap(whatevers -> {
                         //Synchronous, blocking database call
                         ReturnThing returnThing= returnThingRepo.getByWhateverId(whatever.ID);
                         }
                         return returnThing;
                     });
}

现在是的,我知道有一个简单的方法可以被动地做到这一点。这不是我要问的问题(事实上,真正的代码要复杂得多)。

我真正想知道的是,同步数据库调用将对我的性能产生什么影响。整个方法是否仍然是异步非阻塞的(除了在进行db调用的部分,即阻塞期间)?或者这会以某种方式破坏整个反应范式,导致整个事情,从开始到结束,都被阻塞吗?

共有2个答案

池兴邦
2023-03-14

你需要理解反应的关键,你就能自己回答这个问题。反应过程中的每个操作员一次一个项目。每个操作员还具有一个队列,如果操作员忙,可以在其中对项目进行排队。现在考虑下面的代码:

Flux.fromIterable(Arrays.asList(1,2,3,4,5))
    .flatMap(a -> {
         Thread.sleep(2000);
         return Mono.just(a);
    }).subscribe(System.out::println);

您将看到项目每隔2秒打印一次。这是因为平地图的线程被阻塞了2秒,其余元素的项目都排队了。平地图的线程如果想消耗队列中的项目,就必须成为自由的。

在你的例子中,你说数据库调用被阻塞了。这将导致调用线程被阻塞。所以你的方法既不是非阻塞,也不是异步。但是,执行以下操作

Mono.just(whatever)
    .subscribeOn(Schedulers.elastic())
    .flatMap(whatever -> returnThingRepo.getByWhateverId(whatever.ID));

flatMap中,您的方法将变成非阻塞异步。这是因为调用线程在<代码>完成后立即变为空闲。subscribeOn()运算符被调用。

希望这能回答你的问题。

这并没有打破反应范式。在我看来,反应式操作远不止是非阻塞的异步操作。除了NIO,惯用性和简单的多线程功能也是我的一大卖点。

屈浩波
2023-03-14

要记住的金科玉律是,你永远不能让阻塞方法成为非阻塞方法。你可以从另一个角度去做一些琐碎的事情,你可以做各种各样的事情来避免完全破坏反应性范式,但是没有办法让它本质上是异步的。

或者这会以某种方式破坏整个反应范式,导致整个事情,从开始到结束,都被阻塞吗?

不幸的是,比这更糟。假设它不会使应用程序崩溃,那么在执行阻塞数据库调用时,它将导致少数几个反应线程之一(或者可能是单个反应线程)阻塞。这意味着需要使用该线程的所有其他反应性操作(这很可能是整个应用程序)都必须等到阻塞数据库调用完成后才能进行调度,这对性能造成了严重影响。

处理这些情况(需要从响应链进行阻塞调用)的公认方法是使用有界弹性调度程序,它将执行委托给后端线程池,以便不束缚主事件线程。

 类似资料:
  • 问题内容: 操作系统是否正确处理? 还是我必须打电话给flock()? 问题答案: 虽然OS不会崩溃,并且文件系统不会被破坏,呼叫被 不 保证的广告是原子的,除非有问题的文件描述符是一个管道,数据的写入量字节或更少。标准的相关部分: 尝试写入管道或FIFO具有几个主要特征: * 原子/非原子:如果一个操作中写入的总量未与任何其他进程的数据交错,则写入是原子的。当有多个作者将数据发送到单个读者时,此

  • 我有一个使用WebFlux和REST API的反应性Spring应用程序。每当用户调用我的API,我都需要调用一个公开WSDL的SOAP服务,执行一些操作并返回结果。 如何将对SOAP服务的调用与反应性WebFlux框架结合起来? 在我看来,我可以用两种不同的方式来做: 使用WebFlux的WebClient构造并发送SOAP消息。 在Mono/flux中使用WebServiceGatewaySu

  • 问题内容: 在具有并发访问的程序中使用映射时,是否需要在函数中使用互斥体来 读取 值? 问题答案: 读者众多,没有作家可以: https://groups.google.com/d/msg/golang- nuts/HpLWnGTp-n8/hyUYmnWJqiQJ 一个作家,没有读者是可以的。(否则,地图不会太好。) 否则,如果至少有一个作家,而作家或读者至少还有一个,那么 所有 读者 和 作家都

  • 问题内容: 如果我提交的表单的操作字段为空,则它提交到当前页面-ajax请求就是这种情况吗? 问题答案: 没错,它会提交到当前页面。 参考,jQuery文档: url (字符串) 默认值:当前页面 一个字符串,其中包含将请求发送到的URL。 资源

  • 我需要进行异步调用,并使用其中存在的一些值对同一服务进行多次调用。将这些调用的响应与第一个调用结合起来,然后返回。 例如,当我第一次调用时,我会在JSON下面看到一个ID列表。现在,我必须使用这些ID对一个服务进行多次调用,并列出它们的响应列表,然后通过在同一个JSON中添加它们将其发送到下游。 我试过使用zipWhen和 但是结果列表总是以空或空的形式出现。我们如何才能做到这一点?我是不是漏了什

  • 问题内容: 我从以下代码调用函数: 我的功能是 我怎么只能拨打一次ajax电话?所以当内容被加载并且页面不被拒绝时不加载ajax吗?我尝试做布尔变量,但什么也没做,我支持这是因为我调用了everytime函数。请给我一个想法。 谢谢 问题答案: 当您想对该事件做某事时。 确定何时已加载数据。 或在您想一次调用时使用。 参考