背景:我这周才刚刚开始使用 Quarkus,尽管我之前使用过一些流媒体平台(尤其是 scala 中的 http4s/fs2)。
使用 quarkus reactive(与 mutiny)和任何响应式数据库客户端(mutiny reactive postgres、reactive elasticsearch 等)我有点困惑如何正确管理阻塞调用和线程池。
quarkus 文档建议使用命令式代码或 cpu 密集型代码进行注释,@Blocking
以确保将其转移到工作池而不阻塞 IO 池。这是有道理的。
考虑以下:
public class Stuff {
// imperative, cpu intensive
public static int cpuIntensive(String arg) { /* ... */ }
// blocking IO
public static List<Integer> fetchFromDb() { /* ... */ }
// reactive IO
public static Multi<String> fetchReactive() { /* ... */ }
// reactive IO with CPU processing
public static Multi<String> fetchReactiveCpuIntensive(String arg) {
fetchReactive() // reactive fetch
.map(fetched -> cpuIntensive(arg + fetched)) // cpu intensive work
}
}
我不清楚在上述每种情况下会发生什么,以及如果从没有注释的 resteasy-reactive 休息端点调用它们,它们会在哪里执行@Blocking
。
据推测,在没有@Blocking
. 但是,Uni
对于“不安全”的代码来说,包装一个阻塞调用是否同样有效?也就是说,任何返回Multi
/的东西都会在池中Uni
有效运行吗?worker
(我将打开有关更好地控制线程池的后续帖子,因为我看不到任何方法可以将反应性 IO 调用“转移”到一个单独的池而不是 CPU 密集型工作,这将是最佳的。)
编辑
这个问题可能暗示我在询问返回类型(Uni
/Multi
与直接对象),但它实际上是关于在任何给定时间选择正在使用的线程池的能力。这个关于命令式到反应式的叛变页面实际上在 某种程度上回答了我的问题,以及叛变基础设施文档,其中指出“默认执行程序已配置为使用 Quarkus 工作线程池。”,叛变线程控制文档处理其余部分我认为。
所以我的理解是这样的:
如果我有一个端点可以有条件地返回非阻塞的东西(例如本地非阻塞缓存命中),那么我可以有效地在 IO 线程上返回任何我想要的方式。但是,如果所述缓存未命中,我可以直接调用响应式客户端或使用 mutiny 对 quarkus 工作池运行阻塞操作。同样,mutiny 提供了在特定线程池(执行程序)上执行任何给定流的控制。
响应式客户端(或在非 IO 池上有效运行的任何东西)可以安全调用,因为 IO 循环只是订阅工作池发出的数据。
最后,似乎我可以将一个 CPU 绑定池与一个 IO 绑定工作池分开配置,并明确地将它们作为executor
s 提供给我需要的任何发射器。所以......我想我现在已经准备好了。