如何将传入的NetSocket处理程序分配到不同的事件循环线程?

时间:2016-10-22 16:44:22

标签: vert.x

我正在尝试使用Vertx实现TCP服务器,接受传入连接,然后处理不同的套接字。由于每个套接字都可以独立处理,属于不同套接字的处理程序应该同时在不同的事件循环线程中运行。

根据Vert.x document

  

标准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(),则处理程序在不同的事件循环线程中运行。

所以,我的问题是如何同时运行这些处理程序?

2 个答案:

答案 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连接处理程序将以循环方式调用。