Vert.x Core基础

Vert.x Core基础

Scroll Down

Vert.x是一个基于Netty的异步编程工具集,它的核心包中提供了编写异步WEB应用的基础API。现在市面上大多数WEB框架依赖于简单的线程策略:每一个请求绑定一个线程,这个线程处理这个请求直到返回响应或失去连接,这种同步I/O模型虽然易于理解,但不仅增加了系统内核调度线程的开销,且各类I/O的阻塞会使得CPU资源无法充分被利用,极大影响了系统的效率,而基于异步I/O的Vert.x能够有效的避免这些问题

Verticle和Event Loop

Verticle是Vert.x部署运行的基本单元,而Event Loop是Vert.x用于调度CPU所使用的线程,Verticle通过将时间分派给Event Loop处理的方式来处理事件。

Verticle

Verticle通过开箱即用的方式提供了一个简单便捷的、可扩展的、类似 Actor Model 的部署和并发模型机制。 一个应用程序通常是由在同一个 Vert.x 实例中同时运行的许多 Verticle 实例组合而成。不同的 Verticle 实例通过向 Event Bus 上发送消息来相互通信

Verticle 种类

有三种不同类型的 Verticle:

  • Stardand Verticle:这是最常用的一类 Verticle —— 它们永远运行在 Event Loop 线程上
  • Worker Verticle:这类 Verticle 会运行在 Worker Pool 中的线程上。一个实例绝对不会被多个线程同时执行
  • Multi-Threaded Worker Verticle:这类 Verticle 也会运行在 Worker Pool 中的线程上。一个实例可以由多个线程同时执行(译者注:因此需要开发者自己确保线程安全)

Event Loop

默认情况一个 Vert.x 实例维护了N(默认情况下N = CPU核数 x 2)个 Event Loop 线程。除了在Worker Verticle外,所有的处理器核只会在同一个Event Loop线程中被调用,永远不会被并发执行。在这种情况下,同时并发执行的Event Loop与CPU核心数直接关联,Event Loop线程的阻塞将会对应用性能产生更大的影响,因此,不要在业务实现中写阻塞代码,如果阻塞了 Vertx 实例中的所有 Event Loop,那么应用就会完全停止 43410120171019164454131679563098.png

运行阻塞式代码

在实际的开发过程中,还是不可避免的会使用到一些同步API,这些API中许多方法都是阻塞式的,但是如上所述,并不能够在Event Loop中直接调用这些阻塞式操作。现有以下两周方式可供选择

  1. 调用executeBlocking方法来执行阻塞式代码并处理结果的异步回调

     vertx.executeBlocking(future -> {
      // 调用一些需要耗费显著执行时间返回结果的阻塞式API
     String result = someAPI.blockingMethod("hello");
      future.complete(result);
     }, res -> {
       System.out.println(res.result());
     });
    
  2. 使用Worker Verticle

     WorkerExecutor executor = vertx.createSharedWorkerExecutor("my-worker-pool");
     executor.executeBlocking(future -> {
      // 调用一些需要耗费显著执行时间返回结果的阻塞式API
      String result = someAPI.blockingMethod("hello");
     future.complete(result);
     }, res -> {
       System.out.println("The result is: " + res.result());
     });
    

Worker Executor 在不需要的时候必须被关闭:

    executor.close();

Context对象

当 Vert.x 传递一个事件给处理器或者调用 Verticle 的 start 或 stop 方法时,它会关联一个 Context 对象来执行。

  • 在Stardand Verticle中:Context对象会绑定在一个特定的Event Loop线程上,所以在该Context上执行的操作一直会在同一个Event Loop线程中
  • 在Worker Verticle中:Context是一个 Worker Context,并且所有的操作运都会运行在 Worker 线程池的线程上
  • 一个 Context 对应一个 Event Loop 线程(或 Worker 线程),但一个 Event Loop(或 Worker 线程)可能对应多个 Context

Vert.x定时器(延时操作&定时)

vertx对象提供了setTimer方法和setPeriodic分别来进行延时操作和定时操作,这两个方法都接收一个延时时间和一个执行业务的Handler为参数,方法的返回值都为计时器的Id

延时操作(一次性)

通过vertx对象的setTimer方法来设置延时操作触发

    long timerID = vertx.setTimer(1000, id -> {
     System.out.println("And one second later this is printed");
    });
    
    System.out.println("First this is printed");

定时器

通过vertx对象的setPeriodic方法来设置定时器

    long timerID = vertx.setPeriodic(1000, id -> {
    System.out.println("And every second this is printed");
    });

    System.out.println("First this is printed");