3.3 黄金法则

  这里的黄金法则不是说按照这个法则你就能得到好的性能,不按照这个法则你就只能得到正常的性能,而是类似于“铁律”的意思,使用 Vert.x,你一定要遵照这一点。这条黄金法则是:

  不要阻塞事件循环。

  开发过客户端程序的同事应该都知道,执行耗时操作的代码应当放到 Worker线程 中执行,用户的 UI线程 应该永远保持响应。Vert.x 中的事件循环就像客户端中的 UI线程 一样,不允许执行阻塞或者耗时操作(包括有可能阻塞或耗时的操作),包括但不限于:

  • Thread.Sleep
  • Socket 读数据
  • 发送一个HTTP请求并等待响应
  • 等待一个锁
  • 执行了一个显著耗时的内存操作

  我们前面说过,一个 Verticle 里的所有事件处理函数都是运行在一个 事件循环 中,是单线程的,想象一下本来一秒钟可以处理10000个请求(每个 请求 都是一个 事件)的网站服务器程序被一个耗时操作卡了2秒钟是什么感觉,这比用户 UI线程 卡2秒严重多了,这可能是一万个用户同时多等待了2秒,按照某些老师的思路,你浪费了大家5个多小时的时间。

  不过这个 黄金法则 并不会影响我们实现下面的业务逻辑:

  • 等待一段时间,再运行后续代码
  • Socket 读数据,再运行后续代码
  • 发送一个 HTTP POST 请求并收到响应,再运行后续代码
  • 等待一个锁,再运行后续代码
  • 执行了一个显著耗时的内存操作,再运行后续代码

  ——只要你调用 Vert.x 提供的异步无阻塞的 API:

  • Vertx.setTimer
  • NetSocket.handler
  • HttpClient.post
  • SharedData.getLock
  • Vertx.executeBlocking

  它们会完成这些耗时操作并通知你结果,你只需要在 处理函数 中处理这个结果就可以了:

  这样设计有什么好处呢?具体有以下两点:

  1. 通过线程复用提高系统资源利用率,避免高并发启动过多用户线程。如果网络服务器对于每个请求都新开一个用户线程,那么高并发时线程数会显著上升,线程上下文切换将会消耗大量的CPU资源。而 Vert.x 通过使用线程池,复用特定数量的线程,将阻塞的 IO操作 交由操作系统或其他线程异步执行,使用户线程只需要运行无阻塞的 事件处理函数,保证了及时响应以及高性价比的并发支持。
  2. 减少了资源竞争,天然的线程安全。因为每个 Verticle 中的用户代码都是单线程的,所以我们可以在 Verticle 中放心的寄存状态变量而不用担心线程安全问题,这使 Vert.x 非常适合开发 有状态 的服务。

results matching ""

    No results matching ""