快速解决:
WorkerExecutor executor = vertx.createSharedWorkerExecutor("my-worker-pool");
executor.executeBlocking(future -> {
// 调用一些需要耗费显著执行时间返回结果的阻塞式API
String result = someAPI.blockingMethod("hello");
future.complete(result);
}, res -> {
System.out.println("The result is: " + res.result());
});
了解更多:
https://vertxchina.github.io/vertx-translation-chinese/core/Core.html
如果您的应用程序没有响应,可能这是一个迹象,表明您在某个地方阻塞了Event Loop。为了帮助您诊断类似问题,若 Vert.x 检测到 Event Loop 有一段时间没有响应,将会自动记录这种警告。若您在日志中看到类似警告,那么您需要检查您的代码。比如:
Thread vertx-eventloop-thread-3 has been blocked for 20458 ms
Vert.x 还将提供堆栈跟踪,以精确定位发生阻塞的位置。
如果想关闭这些警告或更改设置,您可以在创建 Vertx
对象之前在 VertxOptions
中完成此操作。
运行阻塞式代码
在一个完美的世界中,不存在战争和饥饿,所有的API都将使用异步方式编写,兔兔和小羊羔将会在阳光明媚的绿色草地上手牵手地跳舞。
但是……真实世界并非如此(您最近看新闻了吧?)
事实是,很多,也非所有的库,特别是在JVM生态系统中有很多同步API,这些API中许多方法都是阻塞式的。一个很好的例子就是 JDBC API,它本质上是同步的,无论多么努力地去尝试,Vert.x都不能像魔法小精灵撒尘变法一样将它转换成异步API。
我们不会将所有的内容重写成异步方式,所以我们为您提供一种在 Vert.x 应用中安全调用"传统"阻塞API的方法。
如之前讨论,您不能在 Event Loop 中直接调用阻塞式操作,因为这样做会阻止 Event Loop 执行其他有用的任务。那您该怎么做?
可以通过调用 executeBlocking
方法来指定阻塞式代码的执行以及阻塞式代码执行后处理结果的异步回调。
vertx.executeBlocking(future -> {
// 调用一些需要耗费显著执行时间返回结果的阻塞式API
String result = someAPI.blockingMethod("hello");
future.complete(result);
}, res -> {
System.out.println("The result is: " + res.result());
});
默认情况下,如果 executeBlocking
在同一个上下文环境中(如:同一个 Verticle 实例)被调用了多次,那么这些不同的 executeBlocking
代码块会 顺序执行(一个接一个)。
若您不需要关心您调用 executeBlocking
的顺序,可以将 ordered
参数的值设为 false
。这样任何executeBlocking
都会在 Worker Pool 中并行执行。
另外一种运行阻塞式代码的方法是使用 Worker Verticle。
一个 Worker Verticle 始终会使用 Worker Pool 中的某个线程来执行。
默认的阻塞式代码会在 Vert.x 的 Worker Pool 中执行,通过 setWorkerPoolSize
配置。
可以为不同的用途创建不同的池:
WorkerExecutor executor = vertx.createSharedWorkerExecutor("my-worker-pool");
executor.executeBlocking(future -> {
// 调用一些需要耗费显著执行时间返回结果的阻塞式API
String result = someAPI.blockingMethod("hello");
future.complete(result);
}, res -> {
System.out.println("The result is: " + res.result());
});
Worker Executor 在不需要的时候必须被关闭:
executor.close();
当使用同一个名字创建了许多 worker 时,它们将共享同一个 pool。当所有的 worker executor 调用了close
方法被关闭过后,对应的 worker pool 会被销毁。
如果 Worker Executor 在 Verticle 中创建,那么 Verticle 实例销毁的同时 Vert.x 将会自动关闭这个 Worker Executor。
Worker Executor 可以在创建的时候配置:
int poolSize = 10;
// 2分钟
long maxExecuteTime = 120000;
WorkerExecutor executor = vertx.createSharedWorkerExecutor("my-worker-pool", poolSize, maxExecuteTime);
请注意:这个配置信息在 worker pool 创建的时候设置。