首页 > 解决方案 > vertx如何创建eventloop线程

问题描述

我试过DeploymentOptions.setEventLoopPoolSize(even number x)了,但它实际上创建了 x/2 个线程,奇数是可以的。

代码很简单,如下所示:

public final class Bootstrap {

    private static final VertxOptions VERTX_OPTIONS;
    private static final Vertx VERTX;

    private static final DeploymentOptions HTTP_SERVER_DEPLOYMENT_OPTIONS;

    static {
        VERTX_OPTIONS = new VertxOptions();
        VERTX_OPTIONS.setEventLoopPoolSize(22);
        System.out.println("Event Loop Pool Size: " + VERTX_OPTIONS.getEventLoopPoolSize());

        VERTX = Vertx.vertx(VERTX_OPTIONS);

        HTTP_SERVER_DEPLOYMENT_OPTIONS = new DeploymentOptions();
        HTTP_SERVER_DEPLOYMENT_OPTIONS.setInstances(24);
        HTTP_SERVER_DEPLOYMENT_OPTIONS.setWorkerPoolName("http-server-worker");//remove this line you can create the right number of thread
    }

    public static void main(String[] args) {
        VERTX.deployVerticle(MyHttpServer.class, HTTP_SERVER_DEPLOYMENT_OPTIONS, ar -> {
            System.out.println("success");
            System.out.println("is Worker? " + HTTP_SERVER_DEPLOYMENT_OPTIONS.isWorker());
        });
    }
}

public class MyHttpServer extends AbstractVerticle {

    @Override
    public void start(Promise<Void> startPromise) throws Exception {

        Router router = Router.router(vertx);
        String content = "I'm " + this + " thread: " + Thread.currentThread() + " router: " + router;

        router.get("/").handler(context -> {
            context.response().end(content);
        });

        vertx.createHttpServer().requestHandler(router).listen(80, ar -> {
            if(ar.succeeded()) {
                System.out.println("server start " + this);
                startPromise.complete();
            } else {
                ar.cause().printStackTrace();
            }
        });
    }
}

wertx-web 3.9.2

打开 Java VisualVM 可以看到设置和不设置 WorkerPoolName 的区别。 Java visualVM image 设置时,EventLoopPoolSize为偶数,实际创建的线程数减半。怎么了setWorkerPoolName()

标签: javanettyvert.x

解决方案


我阅读了源代码并发现该方法

private static EventLoop getEventLoop(VertxInternal vertx) in io.vertx.core.impl.ContextImpl

有个有趣的行为:不管是谁调用这个方法,它都会一个接一个地从一个数组中给你一个EventLoop对象。它实际上是在io.netty.util.concurrent.DefaultEventExecutorChooserFactory.GenericEventExecutorChooser这个内部类中实现的,它有一个方法next ()

    @Override
    public EventExecutor next() {
        return executors[Math.abs(idx.getAndIncrement() % executors.length)];
    }

因此,当您为 EventLoop 创建线程,并准确获取所有对应于偶数(或奇数)索引的 EventLoop 时,将会丢失一半的 EventLoop 数组。

而且,当 vertx 部署 verticles 时,它会查看你是否设置了 WorkerPoolName:

for (Verticle verticle: verticles) {
  WorkerExecutorInternal workerExec = poolName != null ? vertx.createSharedWorkerExecutor(poolName, options.getWorkerPoolSize(), options.getMaxWorkerExecuteTime(), options.getMaxWorkerExecuteTimeUnit()) : null;
  WorkerPool pool = workerExec != null ? workerExec.getPool() : null;
  ContextImpl context = (ContextImpl) (options.isWorker() ? vertx.createWorkerContext(options.isMultiThreaded(), deploymentID, pool, conf, tccl) :
    vertx.createEventLoopContext(deploymentID, pool, conf, tccl));

如果你这样做了,它将为此步骤创建 2 个上下文。这意味着它将调用 getEventLoop() 方法两次以获取每个 Context 的 EventLoop。综上所述,如果设置了poolName,每个Verticle在部署的时候会得到两次EventLoop,但是只会创建一个线程。

不知道是不是bug,因为刚接触vertx两天,也不知道是不是故意设计的。我就是想通过setEventLoopPoolSize()来控制我的线程数方法。


推荐阅读