Vertx, как работает многопоточность

В официальных документах Vertx я прочитал следующий абзац

   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.

И в статье про 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.

Как я понял поправьте пожалуйста, если я что то не так напишу, Vertx работает следующим образом:

Когда мы предоставляем обработчик для блокирующего кода, vertx помещает один поток (не цикл событий) в этот код из пула потоков, который равен количеству ядер, например, у меня 4 ядра, а цикл событий проверяет состояние этого потока после каждой итерации. и если он готов выполнить обработчик, связанный с этим блокирующим кодом, когда все 4 ядра заняты, vertx поместит задачу в очередь для выполнения позже,

Что касается рабочей версии, у нас есть еще один пул потоков, который по умолчанию равен 20, когда мы используем следующий метод: vertx.executeBlocking() мы используем поток из этого пула.

Я правильно понимаю?

(PS) Согласно приведенному ниже ответу нет разницы между кодом блокировки с помощью обработчика и кодом блокировки с помощью обработчика, но с использованием блокировки выполнения.

//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;
                }
    }

// рабочий поток

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

Правильно ли я понимаю, оба кода используют рабочий поток под капотом?

6
0
3 100
1

Ответы 1

Vert.x поддерживает два пула потоков.

Один с потоками цикла событий. По умолчанию это два потока цикла событий на ядро. На 4-ядерной машине у вас будет 8 потоков цикла событий. Каждый неблокирующий код запускается в циклах событий. Если вы развертываете несколько вершин, они обычно равномерно распределяются по потокам цикла событий. Очень важно, чтобы код не блокировался, иначе весь другой код в том же цикле событий блокируется.

Другой пул потоков - это рабочий пул (размер по умолчанию - 20, но он настраивается, см. https://vertx.io/docs/apidocs/io/vertx/core/VertxOptions.html#DEFAULT_WORKER_POOL_SIZE), который является своего рода «классическим» потоком. Когда вы вызываете executeBlocking, фрагмент кода отправляется в поток рабочего пула, поэтому он не блокирует цикл событий.

Когда вы выполняете блокировку, вы предоставляете два обработчика, один, который выполняет код блокировки, он запускается в рабочем потоке, а другой, который получает результат, запускается в цикле событий (вызывающий поток, если хотите)

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());
});

Что касается вашего добавленного вопроса, вы используете здесь JDBC-клиент Vert.x, который под капотом запускает блокирующие части JDBC в рабочем потоке, поэтому вам не нужно об этом заботиться. Итак, да, это в основном то же самое, что писать собственный код доступа JDBC внутри первого, blockingHandler, в операторе executeBlocking. Вы также могли увидеть это в коде JDBC-клиента Vert.x: https://github.com/vert-x3/vertx-jdbc-client/blob/c83138c00390777f3d17ac492f09203e9e92284d/src/main/java/io/vertx/ext/jdbc/impl/actions/AbstractJDBCL66.java

Как насчет блокировки вызовов с помощью обработчиков, таких как JDBC select или insert, например, мы делаем запрос вставки и добавляем к нему обработчик, как цикл событий узнает, когда вставка выполнена?

Almas Abdrazak 13.04.2018 19:12

Для всего выполнения блокировки: обработчик блокировки запускается в рабочем потоке и, как только это будет сделано, помещает результат в будущее, будущее передается в resultHandler, который запускается в цикле событий, таким образом цикл событий получает уведомление. Кстати. клиент Vertx JDBC выполняет вызовы jdbc для вас блокирующим образом, поэтому вам не нужно заботиться об этом самостоятельно.

Gerald Mücke 13.04.2018 20:10

Другие вопросы по теме