我正在尝试使用Vertx实现TCP服务器,接受传入连接,然后处理不同的套接字。由于每个套接字都可以独立处理,属于不同套接字的处理程序应该同时在不同的事件循环线程中运行。
标准Verticle在创建时会被赋予一个事件循环线程,并且使用该事件循环调用start方法。当您调用从事件循环中获取核心API处理程序的任何其他方法时,Vert.x将保证这些处理程序在被调用时将在同一事件循环上执行。
我认为,此代码段可以打印不同的线程名称:
Vertx vertx = Vertx.vertx(); // The number of event loop threads is 2*core.
vertx.createNetServer().connectHandler(socket -> {
vertx.deployVerticle(new AbstractVerticle() {
@Override
public void start() throws Exception {
socket.handler(buffer -> {
log.trace(socket.toString() + ": Socket Message");
socket.close();
});
}
});
}).listen(port);
但遗憾的是,所有处理程序都位于同一个帖子中。
23:59:42.359 [vert.x-eventloop-thread-1] TRACE Server - io.vertx.core.net.impl.NetSocketImpl@253fa4f2: Socket Message
23:59:42.364 [vert.x-eventloop-thread-1] TRACE Server - io.vertx.core.net.impl.NetSocketImpl@465f1533: Socket Message
23:59:42.365 [vert.x-eventloop-thread-1] TRACE Server - io.vertx.core.net.impl.NetSocketImpl@5ab8dac: Socket Message
23:59:42.366 [vert.x-eventloop-thread-1] TRACE Server - io.vertx.core.net.impl.NetSocketImpl@5fc72993: Socket Message
23:59:42.367 [vert.x-eventloop-thread-1] TRACE Server - io.vertx.core.net.impl.NetSocketImpl@38ee66d7: Socket Message
23:59:42.368 [vert.x-eventloop-thread-1] TRACE Server - io.vertx.core.net.impl.NetSocketImpl@6a60a74: Socket Message
23:59:42.369 [vert.x-eventloop-thread-1] TRACE Server - io.vertx.core.net.impl.NetSocketImpl@5f3921e1: Socket Message
23:59:42.370 [vert.x-eventloop-thread-1] TRACE Server - io.vertx.core.net.impl.NetSocketImpl@39d41024: Socket Message
... more than 100+ lines ...
相反的例子类似于this echo server written in BOOST.ASIO。如果使用线程池执行io_service::run()
,则处理程序在不同的事件循环线程中运行。
所以,我的问题是如何同时运行这些处理程序?
答案 0 :(得分:0)
实际上,你做的事与你想要的完全不同。
每次在套接字上收到连接时,都会启动一个新的actor
证明这一点的最简单方法:
Vertx vertx = Vertx.vertx(); // The number of event loop threads is 2*core.
vertx.createHttpServer().requestHandler(request -> {
vertx.deployVerticle(new AbstractVerticle() {
String uuid = UUID.randomUUID().toString(); // Some random unique number
@Override
public void start() throws Exception {
request.response().end(uuid + " " + Thread.currentThread().getName());
}
});
}).listen(8888);
vertx.setPeriodic(1000, r -> {
System.out.println(vertx.deploymentIDs().size()); // Print verticles count every second
});
我使用httpServer只是因为它更容易在浏览器中查看 尽管错误,你仍然会看到你应该收到不同的主题:
fe931b18-89cc-4c6a-9d6a-8565bb1f1c12 vert.x-eventloop-thread-9
277330da-4df8-4e91-bd8f-82c0f62156d0 vert.x-eventloop-thread-11
bbd3207c-80a4-41d8-9be5-b40727badc84 vert.x-eventloop-thread-13
现在你应该怎么做:
// We create 10 workers
for (int i = 0; i < 10; i++) {
vertx.deployVerticle(new AbstractVerticle() {
@Override
public void start() {
vertx.eventBus().consumer("processMessage", (request) -> {
// Do something smart
// Reply
request.reply("I'm on thread " + Thread.currentThread().getName());
});
}
});
}
// This is your handler
vertx.createHttpServer().requestHandler(request -> {
// Only one server, that should dispatch events to workers as quickly as possible
vertx.eventBus().send("processMessage", null, (response) -> {
if (response.succeeded()) {
request.response().end("Request :" + response.result().body().toString());
}
// Handle errors
});
}).listen(8888);
vertx.setPeriodic(1000, r -> {
System.out.println(vertx.deploymentIDs().size()); // Notice that number of workers doesn't change
});
答案 1 :(得分:0)
如果没有更多细节(例如测试机器的核心数量),则无法确定Vert.x将为每个Verticle分配哪个事件循环。
无论如何,每个传入连接部署一个Verticle并不是一个好主意。 Verticle是Vert.x中的部署单位。您通常会为每个“功能”创建一个。
回到您的用例,事件驱动编程的目的正是为了避免每个连接使用一个线程。您可以使用单个事件循环处理很多并发连接。如果您的计算机上有多个核心,那么您可以部署多个Verticle实例以使用它们(每个核心1个事件循环)。
int processors = Runtime.getRuntime().availableProcessors();
Vertx vertx = Vertx.vertx();
vertx.deployVerticle(TCPServerVerticle.class.getName(), new DeploymentOptions().setInstances(processors));
public class TCPServerVerticle extends AbstractVerticle {
@Override
public void start(Future<Void> startFuture) throws Exception {
vertx.createNetServer().connectHandler(socket -> {
socket.handler(buffer -> {
log.trace(socket.toString() + ": Socket Message");
socket.close();
});
}).listen(port, ar -> {
if (ar.succeeded()) {
startFuture.complete();
} else {
startFuture.fail(ar.cause());
}
});
}
}
使用Vertx TCP server sharing连接处理程序将以循环方式调用。