Vert.x学习笔记-什么是Verticle

news2025/4/7 8:30:26

什么是Verticle

Verticle是Vert.x应用中的基本编程单元,类似于Java中的Servlet、Pojo Bean或Akka中的Actor。它可以使用不同的编程语言实现,并且这些由不同编程语言实现的Verticle可以封装到一个模块中,进而部署到一个Vert.x应用中。Verticle可分为两种类型:标准VerticleWorker Verticle

  • 标准Verticle运行在Vert.x实例的事件循环线程中,当有事件发生时,在事件循环线程中回调Verticle实例中的event handler。
  • Worker Verticle在background workers线程池中执行,该线程池的大小缺省为40。

在事件循环线程上运行代码的基本原则是不能阻塞,并且代码的执行要足够快,但是在很多场合中确实难以避免会有阻塞的代码出现,vert.x提供了两种处理此类情况的方法: Worker VerticleexecuteBlocking方法

在这里插入图片描述

Worker Verticle

Worker Verticle是一种特殊的Verticle,它不是在事件循环线程上执行的,而是在专门的工作线程上执行的。工作线程来自一个特殊的工作线程池,开发人员也可以自定义工作线程池,将Worker Verticle部署给工作线程池。

Worker Verticle处理事件的方式与事件循环一致,只不过它可用人异常的时间来处理事件,Worker Verticle有以下两个特点:

  • Worker Verticle不会与某一个工作线程绑定,每一次运行可能是在不同的工作线程上的
  • 在任意的时刻,Worker Verticle只能被单个工作线程访问

Working Verticle和事件循环一样,都是单线程的,不同的地方是事件循环线程固定,Worker Verticle依附的线程不固定,每次可能会从线程池中找新的线程处理

Workder Verticle示例

public class WorkerVerticle extends AbstractVerticle{

  private final Logger logger = LoggerFactory.getLogger(WorkerVerticle.class);

  @Override
  public void start() {
    vertx.setPeriodic(10_000, id -> {
      try {
        logger.info("Zzz...");
        Thread.sleep(8000);
        logger.info("Up!");
      } catch (InterruptedException e) {
        logger.error("Woops", e);
      }
    });
  }

  public static void main(String[] args) {
    Vertx vertx = Vertx.vertx();
    DeploymentOptions opts = new DeploymentOptions()
      .setInstances(2) //创建两个实例
      .setWorker(true); //通过该标志来确定实例化的是否为Worker Verticle
    vertx.deployVerticle("xxx.WorkerVerticle", opts); //由于单次要创建两个实例,所以需要用全路径,如果只是创建单个Verticle就可以用new或者全路径
  }
}

在这里插入图片描述

从代码的执行结果也可以明显的看出来,每一次执行Worker Verticle的并不是固定的线程

在这里插入图片描述

executeBlocking方法

虽说Worker Verticle处理阻塞任务是一个非常优秀的方案,但是将阻塞代码全部抽取到Worker Verticle也不一定是完全合理的,这样可能会造成有非常多的执行很小功能的Worker Verticle,并且造成各个类无法形成一个独立的功能单元
运行阻塞式代码的另一种方式是通过Vertx类中的executeBlocking方法。该方法将一些阻塞的代码的执行转移到工作线程上,然后会以新事件的形式将结果发送回事件循环,执行流程如下图所示:

在这里插入图片描述

代码示例

public class Offload extends AbstractVerticle {

  private final Logger logger = LoggerFactory.getLogger(Offload.class);

  @Override
  public void start() {
    vertx.setPeriodic(5000, id -> {
      logger.info("Tick");
      vertx.executeBlocking(this::blockingCode, this::resultHandler);
    });
  }

  private void blockingCode(Promise<String> promise) { // promise对象用于返回结果的传递
    logger.info("Blocking code running");
    try {
      Thread.sleep(4000);
      logger.info("Done!");
      promise.complete("Ok!"); //promise完成并返回OK
    } catch (InterruptedException e) {
      promise.fail(e); //promise失败并返回异常
    }
  }

  private void resultHandler(AsyncResult<String> ar) { //在事件循环线程上处理阻塞代码的结果
    if (ar.succeeded()) {
      logger.info("Blocking code result: {}", ar.result());
    } else {
      logger.error("Woops", ar.cause());
    }
  }

  public static void main(String[] args) {
    Vertx vertx = Vertx.vertx();
    vertx.deployVerticle(new Offload());
  }
}
执行结果:

在这里插入图片描述

从上图的执行 结果就可以看出来,事件循环线程是固定不变的,但是执行executeBlocking方法的线程每次执行都可能是会变化的,并且是worker线程来进行执行的

默认情况下,当Vert.x有连续的多个executeBlocking方法时,会按照其调用顺序获得执行结果,executeBlocking方法还有一个带布尔参数类型的重载( Future<@Nullable T> executeBlocking(Handler<Promise> blockingCodeHandler, boolean ordered);),当该参数被设置为false时,任务执行完成后立即会将结果返回给事件循环,而不再遵循executeBlocking的调用顺序

在这里插入图片描述

Verticle 运行环境有Context

在这里插入图片描述
根据上图,我们来详细阐述一下Verticle相关的一些内容
Verticle对象本质是两个对象的组合,分别是:Vert.x和Context

  • Vertx对象: 该Verticle对象所属的Vert.x实例
  • Context对象: 记录Verticle上下文信息的实例,Verticle借助Context对象将事件分派到各个处理程序中

Vert.x实例提供了许多核心API来声明事件处理程序

Vert.x实例由多个Verticle共享,通常每个JVM程序只需要一个Vert.x实例

Verticle Context 可访问此Verticle的事件处理程序的执行线程,事件的来源有很多,比如数据库驱动程序、定时器程序、Http服务器程序,实际环境中,事件更多的是由其它线程触发的,例如Netty接收连接的线程
用户自定义的事件处理程序借助Verticle Context运行,Verticle Context使得我们可以在Verticle分配到的事件循环上执行事件处理程序,从而遵循Vert.x的线程模型。

Worker Verticle 与 Context

在这里插入图片描述

Worker Verticle事件处理程序由工作线程池中的某个工作线程执行,初次之外,Worker Verticle与事件循环的情况基本一致

Context

Verticle Context是Vert.x框架中的一种机制,用于管理和执行Verticle。当Vert.x提供一个事件的处理程序或调用Verticle的开始或停止的方法时,执行与Context相关联。在Verticle中,Context通常是事件循环 context绑定特定的事件循环线程。因此,对于这方面的执行总是发生在该完全相同的事件循环线程。在worker verticles和运行内嵌阻塞代码worker context的情况下将使用一个线程从worker线程池的执行关联。

Verticle的Context对象可以通过Vert.x的getOrCreateContext()方法获取,虽然Context对象几乎都是与Verticle相关联的,单实际上也可以在Verticle之外创建Context对象

  • 从Vert.x上下文环境中调用 getOrCreateContext()方法时,会返回当前的Context对象,如Verticle Context
  • 从非Vert.x上下文环境中调用getOrCreateContext()方法时,会创建一个新的Context对象
    下面的代码就是在非Vert.x上下文环境(JVM进程的主线程)中创建了Context
public class ThreadsAndContexts {

  private static final Logger logger = LoggerFactory.getLogger(ThreadsAndContexts.class);

  public static void main(String[] args) {
    createAndRun();
    dataAndExceptions();
  }

  private static void createAndRun() {
    Vertx vertx = Vertx.vertx();

    vertx.getOrCreateContext()
      .runOnContext(v -> logger.info("ABC")); //Lambda表达式在Vert.x上下文线程上执行

    vertx.getOrCreateContext()
      .runOnContext(v -> logger.info("123"));
  }

  private static void dataAndExceptions() {
    Vertx vertx = Vertx.vertx();
    Context ctx = vertx.getOrCreateContext();
    ctx.put("foo", "bar"); //上下文中可以保存任意的键值对

    ctx.exceptionHandler(t -> { //还可以声明一个异常处理程序
      if ("Tada".equals(t.getMessage())) {
        logger.info("Got a _Tada_ exception");
      } else {
        logger.error("Woops", t);
      }
    });

    ctx.runOnContext(v -> {
      throw new RuntimeException("Tada"); 
    });

    ctx.runOnContext(v -> {
      logger.info("foo = {}", (String) ctx.get("foo"));
    });
  }
}

当事件处理程序的实现跨越了多个类时,不妨用Context来携带数据,这样可能比较有用,否则,不如直接使用某个类的变量

如果某个事件处理程序可能抛出异常,则异常处理程序会变得非常重要。

在这里插入图片描述

桥接Vert.x线程和非Vert.x线程

在编写Vert.x代码的时候,通常不需要同Vert.x的Context打交道,但有一种情况例外:我们不得不使用某些第三方代码,这些代码内置了自己的线程模型,而我们又想让他们与Vert.x协同工作,下面是一个非常常用的解决方法:

public class MixedThreading extends AbstractVerticle {

  private final Logger logger = LoggerFactory.getLogger(MixedThreading.class);

  @Override
  public void start() {
    Context context = vertx.getOrCreateContext(); //提前获取Verticle的Context
    new Thread(() -> {
      try {
        run(context);
      } catch (InterruptedException e) {
        logger.error("Woops", e);
      }
    }).start();
  }

  private void run(Context context) throws InterruptedException {
    CountDownLatch latch = new CountDownLatch(1);
    logger.info("I am in a non-Vert.x thread");
    context.runOnContext(v -> { //runOnContext方法确保这些代码在事件循环线程上执行的
      logger.info("I am on the event-loop");
      vertx.setTimer(1000, id -> {
        logger.info("This is the final countdown");
        latch.countDown();
      });
    });
    logger.info("Waiting on the countdown latch...");
    latch.await();
    logger.info("Bye!");
  }

  public static void main(String[] args) {
    Vertx vertx = Vertx.vertx();
    vertx.deployVerticle(new MixedThreading());
  }
}

上面的代码创建了一个非Vert.x线程,先从Verticle上获取Context对象,再将它传递给非Vert.x线程,以便在非Vert.x线程环境中调用时间循环线程来执行一些代码

总结

  • Verticle是Vert.x应用程序中处理异步事件的核心组件
  • 事件循环负责处理异步的IO事件,它不应该被阻塞,也不应该用来处理耗时很长的任务
  • Worker Verticle可用于处理阻塞的IO事件,或者耗时的任务
  • 借助事件循环上下文,开发人员可以在代码中混合使用Vert.x线程和非Vert.x线程

在这里插入图片描述

拓展

下面是与Vert.x相关的一些其它博文链接,希望可以帮助大家进一步的了解Vert.x的相关知识

Vert.x学习笔记-异步编程和响应式系统

Vert.x学习笔记-什么是Vert.x

Vert.x学习笔记-Vert.x的基本处理单元Verticle

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1198916.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

海康威视嵌入式软件一面(技术面)

海康威视技术面试大部分都是基础问题和牛客上的问题&#xff0c;最后还有手撕代码部分也是牛客原题&#xff0c;总体中等偏难。 一、问答题 1.什么是野指针&#xff0c;野指针如何形成 【C语言基础】野指针与空指针_野指针和空指针-CSDN博客 2.const和static作用和区别 sta…

Java算法(七):随机产生验证码 前后端验证码比对处理 实战思路步骤

Java算法&#xff08;七&#xff09; 随机产生验证码 package com.liujintao.random;import java.util.Random; import java.util.Scanner;public class RandomNumber {/*** 该函数调用验证码所有的函数&#xff0c;完成验证码模块功能开发* param args*/public static void …

2.1 CE修改器:精确数值扫描

本关是CE修改器的第一关&#xff0c;用户需要通过 Cheat Engine 工具完成精确扫描值。在这个练习中&#xff0c;需要将一个特定的数值&#xff08;健康值&#xff09;改变为 1000。首先&#xff0c;要确保数值类型设置正确&#xff0c;默认的是2字节或4字节。接着&#xff0c;选…

Tkinter,一个轻量级的Python GUI库

欢迎关注作者微信公众号&#xff1a;愤怒的it男 Tkinter&#xff08;即 tk interface&#xff0c;简称“Tk”&#xff09;本质上是对Tcl/Tk软件包的Python接口封装&#xff0c;属于Python自带的标准库&#xff0c;安装好Python后可以直接使用Tkinter库而无须另行安装。Tkinter库…

亲身体验告诉你:亚马逊云科技海外服务器是否值得一试?

前言 在当今数字化时代&#xff0c;云计算已经成为企业和个人发展的重要支撑。亚马逊云科技作为全球领先的云计算服务提供商&#xff0c;其海外服务器备受瞩目。然而&#xff0c;对于一些用户来说&#xff0c;是否值得一试亚马逊云科技的海外服务器仍然是一个疑问。本文将通过亲…

深入了解SpringMvc接收数据

目录 一、访问路径&#xff08;RequestMapping&#xff09; 1.1 访问路径注解作用域 1.5 路径精准&#xff08;模糊&#xff09;匹配 1.2 访问路径限制请求方式 1.3 进阶访问路径请求注解 1.4 与WebServlet的区别 二、接收请求数据 2.1 请求param参数 2.2 请求路径参数 2.3 请求…

MySQL数据库实验记录

输入密码 显示数据库 mysql命令以分号;结束 创建数据库 建表 写错了就会报错 没选数据库也会报错

GEE:计算有效像素占比(统计有效像素数量、像素总数)

作者:CSDN @ _养乐多_ 在GEE中进行遥感数据处理的时候,经常会由于去云,导致影像出现空洞,只有部分像素可用,或者在进行特殊处理时,只对有效像素进行处理,但是我们不知道有效像素数量和占比,无法对结果做出准确的分析。这个时候就需要统计有效像素数量占比。 本文记录…

【论文笔记】Denoising Diffusion Probabilistic Models

Pre Knowledge 1.条件概率的一般形式 P ( A , B ) P ( B ∣ A ) P ( A ) P(A,B)P(B|A)P(A) P(A,B)P(B∣A)P(A) P ( A , B , C ) P ( C ∣ B , A ) P ( B , A ) P ( C ∣ B , A ) P ( B ∣ A ) P ( A ) P(A,B,C)P(C|B,A)P(B,A)P(C|B,A)P(B|A)P(A) P(A,B,C)P(C∣B,A)P(B,A)P…

Python之函数进阶-nonlocal和LEGB

Python之函数进阶-nonlocal和LEGB nonlocal语句 nonlocal:将变量标记为不在本地作用域定义&#xff0c;而是在上级的某一级局部作用域中定义&#xff0c;但不能是全局作用域中定义。 函数的销毁 定义一个函数就是生成一个函数对象&#xff0c;函数名指向的就是函数对象。可…

72 内网安全-域横向CSMSF联动及应急响应初识

目录 演示案例:MSF&CobaltStrike联动ShellWEB攻击应急响应朔源-后门,日志WIN系统攻击应急响应朔源-后门,日志,流量临时给大家看看学的好的怎么干对应CTF比赛 涉及资源 权限维持留到后面在补充&#xff0c;先把后面的知识点给大家讲起来&#xff0c;因为权限维持它是我们前期…

HBuilderX vue项目打包上传到服务器

完成后有个’dist’目录,把真个目录通过FTP 上传到服务器,Mac电脑使用cyberduck 上传 服务器使用‘宝塔’进行一件部署,基本上就是傻瓜式的点击下一步

软件过程模型分析与适应场景: 瀑布、原型、增量、螺旋、组件化和统一模型简介

软件过程模型&#xff1a; 瀑布模型 ​ 有很强的前后关联性&#xff0c;前一阶段的输出是后一阶段的输入&#xff0c;而且不可回溯性。 适应场景&#xff1a; ​ 软件开发人员经验丰富​ 需求变化少&#xff0c;变更少&#xff0c;可以一次性获取全部需求​ 项目风险低&…

【开放视频+文档】Spinnaker多云持续部署实践

Hello, 首先&#xff0c;继续感谢大家持续的关注&#xff01; 这次我们已经将《Spinnaker实践》课程 实践文档课程笔记实验源码视频回放 全部免费开放给所有的技术人员。文档库视频基于语雀&#xff0c;扫描图片二维码可以获取语雀文档链接“https://www.yuque.com/devopsgr…

Web APIs——正则表达式使用

1、什么是正则表达式 正则表达式&#xff08;Regular Expression&#xff09;是用于匹配字符串中字符组合的模式。在JavaScript中&#xff0c;正则表达式也是对象 通常用来查找、替换那些符合正则表达式的文本&#xff0c;许多语言都支持正则表达式 1.1 正则表达式使用场景 例如…

nodejs多版本管理

背景 在开发过程中经常会用到不同的nodejs版本&#xff0c;程序在不同版本之间又可能不兼容的情况。一般的做法就是卸载nodejs然后安装需要的版本&#xff0c;这样太过于麻烦。实际上跟conda一样&#xff0c;可以做多版本的管理 解决方法 安装nvm管理nodejs版本&#xff0c;…

第2关:还原键盘输入(list)

题目&#xff1a; 知识点&#xff1a; 列表list相较于数组&#xff1a; 优势&#xff1a;可在任意指定位置插入或者删除元素而不影响列表其他地方 。 劣势&#xff1a;无法直接进行下标索引&#xff0c;需要迭代器it逐个遍历。 代码&#xff1a; #include <iostream>…

(2023|CVPR,扩散,主体标识符,先验保存损失)DreamBooth:微调文本到图像的扩散模型以实现主题驱动的生成

DreamBooth: Fine Tuning Text-to-Image Diffusion Models for Subject-Driven Generation 公众号&#xff1a;EDPJ&#xff08;添加 VX&#xff1a;CV_EDPJ 或直接进 Q 交流群&#xff1a;922230617 获取资料&#xff09; 目录 0. 摘要 1. 简介 2. 相关工作 3. 方法 3.…

【JAVA进阶篇】与数据结构结合?这些知识你应该知道

个人主页&#xff1a;【&#x1f60a;个人主页】 系列专栏&#xff1a;【❤️JAVA进阶】 文章目录 前言关与JAVA中的数据结构Java中的数据结构 枚举位集合创建一个初始大小的位集合设置特定的位从另一个位集合中复制位迭代位集合中设置为1的位将位集合转换为字节数组将字节数组…

【中间件篇-Redis缓存数据库05】Redis集群高可用高并发

Redis集群 Redis Cluster是Redis的分布式解决方案&#xff0c;在3.0版本正式推出&#xff0c;有效地解决了Redis分布式方面的需求。当遇到单机内存、并发、流量等瓶颈时&#xff0c;可以采用Cluster架构方案达到负载均衡的目的。之前,Redis分布式方案一般有两种: 1、客户端分…