6
votes

In Vertx official docs I read the following paragraph

   If a result can be provided immediately, it will be returned immediately, otherwise you will usually provide a handler to receive events some time later.
Because none of the Vert.x APIs block threads that means you can use Vert.x to handle a lot of concurrency using just a small number of threads.

And in article about Reactor:

Vert.x works differently here. Instead of a single event loop, each Vertx instance maintains several event loops. By default we choose the number based on the number of available cores on the machine, but this can be overridden.

As I understand, please correct my if I write something wrong, Vertx works in the following way:

When we provide a handler to blocking code, vertx put one thread(not event loop) to this code from thread pool that equals to the number of cores for example I have 4 cores, and event loop check the state of this thread after each iteration and if it ready execute handler that relate to this blocking code, when all 4 cores are busy vertx put task to the queue to be executed later,

What about worker verticle, we have another thread pool that by default is equal to 20, when we use following method: vertx.executeBlocking() we use thread from this pool.

Is my understanding correct?

(PS) According to the asnwer below there is no difference between blocking code with handler and blocking code with handler but using execute blocking

//jdbc
    connection.execute("insert into test values (1, 'Hello'), (2, 'World')", insert -> {

              // query some data with arguments
              connection.queryWithParams("select * from test where id = ?", new JsonArray().add(2), rs -> {
                if (rs.failed()) {
                  System.err.println("Cannot retrieve the data from the database");
                  rs.cause().printStackTrace();
                  return;
                }
    }

//worker thread

vertx.executeBlocking(e->{},handler->{});

Is my understanding right, both codes use worker thread under the hood?

1

1 Answers

7
votes

Vert.x maintains two thread-pools.

One with the event-loop threads. Which are by default two event-loop threads per core. On a 4 core machine, you'll have 8 event-loop threads. Every non blocking code is run on the event loops. If you deploy multiple verticles, they usually evenly distributed on the event loop threads. It's crucial the code doesn't block otherwise all other code on the same event loop is blocked.

The other thread pool is the worker pool (the default size is 20, but that's configurable, see https://vertx.io/docs/apidocs/io/vertx/core/VertxOptions.html#DEFAULT_WORKER_POOL_SIZE), which is kind of "classic" threading. When you invoke executeBlocking the piece of code is dispatched to a thread of the worker pool so it doens't block the event loop.

When you execute blocking, you provide two handlers, one that executes the blocking code, this is run on the worker thread, and the other - which receives the result - is run on the event loop (the caller thread, if you like)

vertx.executeBlocking(fut -> {
  //blocking code, run on the worker thread
  fut.complete("my result");
}, res -> {
  //non blocking code running on the event loop thread
  System.out.println(res.result());
});

Regarding your added question, you're using the Vert.x JDBC client here, which under the hood runs the blocking JDBC parts on the worker thread, so you don't have to take care of this. So, yes, it basically the same as writing your own JDBC access code inside the first, blockingHandler in an executeBlocking statement. You could see it in the code of the Vert.x JDBC client as well: https://github.com/vert-x3/vertx-jdbc-client/blob/c83138c00390777f3d17ac492f09203e9e92284d/src/main/java/io/vertx/ext/jdbc/impl/actions/AbstractJDBCAction.java#L66