我有简单的vert.x app:
public class Main {
public static void main(String[] args) {
Vertx vertx = Vertx.vertx(new VertxOptions().setWorkerPoolSize(40).setInternalBlockingPoolSize(40));
Router router = Router.router(vertx);
long main_pid = Thread.currentThread().getId();
Handler<ServerWebSocket> wsHandler = serverWebSocket -> {
if(!serverWebSocket.path().equalsIgnoreCase("/ws")){
serverWebSocket.reject();
} else {
long socket_pid = Thread.currentThread().getId();
serverWebSocket.handler(buffer -> {
String str = buffer.getString(0, buffer.length());
long handler_pid = Thread.currentThread().getId();
log.info("Got ws msg: " + str);
String res = String.format("(req:%s)main:%d sock:%d handlr:%d", str, main_pid, socket_pid, handler_pid);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
serverWebSocket.writeFinalTextFrame(res);
});
}
};
vertx
.createHttpServer()
.websocketHandler(wsHandler)
.listen(8080);
}
}
当我将此服务器与多个客户端连接时,我发现它在一个线程中工作。但我希望并行处理每个客户端连接。我该如何更改此代码呢?
答案 0 :(得分:3)
此:
new VertxOptions()。setWorkerPoolSize(40).setInternalBlockingPoolSize(40)
看起来你正在尝试创建自己的HTTP连接池,这可能不是你真正想要的。
Vert.x
和其他基于非阻塞event-loop
的框架的想法是,我们不会尝试1 thread -> 1 connection
亲和关系,而是当一个请求时,当前由事件循环线程正在等待IO - EG来自DB的响应 - 该事件循环线程被释放以服务另一个连接。然后,这允许单个事件循环线程以类似并发的方式为多个连接提供服务。
如果您想充分利用计算机上的所有核心,并且您只需要运行单个verticle
,那么在部署Verticle时将实例数设置为核心数。
IE
Vertx.vertx().deployVerticle("MyVerticle", new DeploymentOptions().setInstances(Runtime.getRuntime().availableProcessors()));
答案 1 :(得分:1)
Vert.x是一个reactive框架,这意味着它使用单个线程模型来处理所有应用程序负载。该模型known比线程模型更好地扩展。
要知道的关键点是,您放入处理程序的所有代码必须永远不会阻止(例如您的Thread.sleep
),因为它会阻止主线程。如果您有阻塞代码(比如说例如JDBC调用),您应该将阻塞代码包装在executingBlocking
处理程序中,例如:
serverWebSocket.handler(buffer -> {
String str = buffer.getString(0, buffer.length());
long handler_pid = Thread.currentThread().getId();
log.info("Got ws msg: " + str);
String res = String.format("(req:%s)main:%d sock:%d handlr:%d", str, main_pid, socket_pid, handler_pid);
vertx.executeBlocking(future -> {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
serverWebSocket.writeFinalTextFrame(res);
future.complete();
});
});
现在所有阻止代码都将在线程池中的一个线程上运行,您可以配置该线程,如其他回复中所示。
如果您想避免编写所有这些执行阻塞处理程序,并且您知道需要执行多个阻塞调用,那么您应该考虑使用worker verticle,因为这些将在事件总线级别进行扩展。
多线程的最后一点是,如果你使用多个线程,你的服务器就不会像单个线程一样高效,例如它无法处理1000万个websockets,因为它有1000万个线程事件。现代机器(我们在2016年)将使您的操作系统调度程序瘫痪。