vertx如何创建事件循环线程

问题描述

我尝试了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()怎么了?

解决方法

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

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数组的一半。

并且,当顶点部署顶点时,它将查看您是否设置了WorkPoolName:

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,tccl));

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

我不知道这是否是一个bug,因为我刚接触vertx两天了,也不知道这是否是故意设计,我只想通过以下方式控制我的线程号setEventLoopPoolSize()方法。