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

如何在另一个线程上运行阻塞代码并使http请求立即返回

夏季萌
2023-03-14

我们开始了一个新的项目与QUOKUS穆特尼,并创建了一堆endpoint与QUOKUS@Funq,到目前为止一切都很好。现在我们想在其中一个endpoint中处理一些非常耗时的事情,我们期望的是,一旦用户单击一个按钮从前端发送超文本传输协议请求并点击这个特定的endpoint,我们将返回202接受立即从后端将耗时的操作处理留在另一个线程中,然后在完成后相应地向用户发送通知电子邮件。

我知道这可以用@AsyncCompletableFuture来完成,但是现在我们想用Mutiny来完成。基于我如何阅读Mutiny留档https://smallrye.io/smallrye-mutiny/guides/imperative-to-reactive,runSubcriptionOn将通过在另一个线程上运行耗时的方法来避免阻塞调用者线程,我的测试显示耗时的代码确实在不同的线程。然而,超文本传输协议请求不会立即返回,它仍然挂起,直到耗时的方法完成执行(正如我在浏览器的开发工具中观察到的)。我是否误解了runSubcriptionOn的工作原理?我如何实现此功能与穆特尼

我的@Funqendpoint如下所示

@Inject
MyService myService;

@Funq("api/report")
public Uni<String> sendReport(MyRequest request) {
    ExecutorService executor = Executors.newFixedThreadPool(10, r -> new Thread(r, "CUSTOM_THREAD"));

    return Uni.createFrom()
        .item(() -> myService.timeConsumingMethod(request))
        .runSubscriptionOn(executor);
} 

编辑:我根据@Ladicek的答案使用Uni找到了解决方案。在深入挖掘Quarkus和Uni之后,我有一个后续问题:

目前,我们的大多数阻塞方法都是而不是服务级别上返回Uni,相反,我们从它们返回的内容(即对象或列表)创建Uni对象,并在它们的endpoint中返回控制器级别上的Uni,如下所示

返回Uni。createFrom()。项目()-

正如@Ladicek所解释的,我不必使用。显式运行subscriptionon,因为IO阻塞方法将自动在工作线程上运行(正如我在服务级别上的方法不返回Uni一样)。这有什么坏处吗?我的理解是,这将导致更长的响应时间,因为它必须在I/O线程和工作线程之间跳转,对吗?

对此的最佳实践是什么?我是否应该总是返回Uni用于服务级别上的阻塞方法,以便它们也可以在I/O线程上运行?如果是这样,我想我将总是需要调用. runSubcriptionOn来在不同的工作线程上运行它,以便I/O线程不被阻塞,对吗?


共有1个答案

黎奇思
2023-03-14

返回一个Uni,基本上就是说当Uni完成时,响应就完成了。您想要的是在线程池上运行操作并返回完整的响应(Uni与否,这无关紧要)。

顺便说一下,您正在为每个请求在方法中创建一个额外的线程池,而不是关闭它。那是错误的。您希望为所有请求创建一个线程池(例如,在@PostConstruct方法中),并在应用程序结束时(在@PreDestroy方法中)理想地将其关闭。

 类似资料:
  • 在过去的几个月里,我一直在阅读C#中的异步等待以及如何正确使用它。 出于实验室练习的目的,我正在构建一个小型Tcp服务器,它应该为连接到它的客户端提供服务。该程序是一个控制台应用程序。 我使用while循环等待连接,如下所示: 所以,到目前为止,我所做的方法ProcessClientAsync被标记为异步无效,我只称之为ProcessClientAsync(客户端),调用将立即返回给调用方。然而,

  • 在完美的世界,将没有战争或饥饿,所有 Api 将使用异步写,阳光明媚,绿色的草地有跳来跳去的兔子和手牵手的小羊羔。 但是,现实世界并不是这样。(你看过新闻最近吗?) 事实是,大多数库,特别是在JVM的生态,Y有许多是同步API,许多的方法有可能阻塞。一个很好的例子是JDBC API - 这是本质上的同步,不管如何努力尝试,Vert.x 不能撒上魔法使之同步。 我们不打算在一夜之间把一切改写成异步,

  • 在一个android服务中,我创建了用于执行一些后台任务的线程。 我遇到一个情况,线程需要在主线程的消息队列上发布特定任务,例如。 有没有方法获取主线程的并从我的另一个线程向它发布/?

  • 我是android新手,我试图发出http post请求,我得到了以下错误,我已经发布了我的代码和我的Logcat的一些行。我应该在另一个类中这样做吗?如果是,如何做,或者只是我必须在当前代码中修复的东西。 logview 02-18 10:03:20.477:W/DalvikVM(3759):ThreadId=15:线程退出,异常未捕获(组=0x4001D760) 02-18 10:03:20.

  • 如另一个问题中所述,当使用Undertow时,所有处理都应该在专用的工作线程池中完成,如下所示: 我知道可用于显式地告诉Undertow在专用的线程池中调度请求以阻止请求。我们可以通过将包装在实例中来修改上面的示例,如下所示: 调用此方法将exchange置于阻塞模式,并创建一个BlockingHttpExchange对象来存储流。当交换处于阻塞模式时,输入流方法变得可用,除了阻塞和非阻塞模式之间

  • 问题内容: 我的一项活动遇到了一个奇怪的问题。从拍照/录像回来时,我正在显示一个对话框,允许用户命名相机。用户按下“确定”后,我将使用所请求的文件名发送给主题,该主题将复制文件(并显示进度对话框)。 由于某种原因,即使我调用,总是在主线程上调用执行复制的函数。 更改呼叫以解决问题。我还是想知道为什么它不起作用… 问题答案: 并且是那里最混乱的运营商。前者确保订阅副作用在指定的调度程序(线程)上发生