vertx框架编程思想
vert.x编程简介:
初始化一个vertx实例,
使用一个启动verticle部署多个verticle,每个verticle都有自己的使命,它们公用一个vertx实例,
vertx是基于事件驱动,verticle部署时指定接受通知后的下一步操作,
它们之间通过eventbus通信,通过eventbus消息总线异步通知每个verticle进行消息处理;
vert.x为verticle提供Event Loop线程执行非阻塞操作,
阻塞操作可以通过vertx实例创建worker-thread线程进行业务相关比较耗时的操作。
为什么选用vertx框架
vertx 线程模型是线程安全的,不需要RD再投入过多的精力考虑多线程下编程的问题,并且初中级程序员也很难写出优雅的多线程代码;vertx框架的扩展组件丰富,支持HTTP2/MONGO/REDIS/CIRCUIT-BREKER/KOTILN/等等
vert.x线程安全的线程模型
为了充分利用多核CPU的性能,Vert.x中提供了一组Event Loop线程 基于Netty的NioEventLoopGroup实现。
每个Event Loop线程都可以处理事件。为了保证线程安全,防止资源争用,
Vert.x保证了某一个Handler总是被同一个Event Loop线程执行,
这样不仅可以保证线程安全,而且还可以在底层对锁进行优化提升性能
注意:在部署Verticle的时候,vert.x会根据配置创建一个Context并绑定到verticle上,以后该verticle绑定的Handler都会在该Context上执行,Context对应唯一一个EventLoop线程,而一个EventLoop线程对应多个Context,so 每个Handler都会在同一个EventLoop线程下执行,从而保证线程的安全
vertx事件模型流程
Vert.x以非阻塞IO的思想来实现高性能,非阻塞IO的实现,基于Event Loop Vertical和Worker Vertical的分离,
在Vert.x中,Event Loop用于接收,并将短业务操作交由其内部的Vertical来处理,该模块是非阻塞的,这样可以保证请求的处理效率;
阻塞任务通过Vert.x的事件机制脱离当前线程,转移到Worker Vertical中执行,并执行结果返回给Event Loop Vertical。
vert.x-worker-thread
vert.x-eventloop-thread
这一过程完成的核心是Event Bus,Event Bus中注册了所有的事件,通过事件匹配完成事件转移和结果返回,从而将整个流程衔接起来。
vertx结合kotlin-coroutines
vertx-lang-kotlin-coroutines集成了Kotlin coroutines,用于执行异步操作和事件处理。
这导致看起来像在使用同步执行代码的编程模型,但它并不阻塞内核线程。
vertx-lang-kotlin-coroutines使用协程: 协程是非常轻量级的线程,不同于底层内核线程,
因此当协程需要“阻塞”时,它将被暂停并释放其当前的内核线程,以便另一个协程可以处理事件
coroutines是异步回调的替代者
//标准vert.x timerAPI写法
vertx.setTimer(1000, tid -> {
System.out.println("Event fired from timer")
});
//使用coroutines
launch(vertx.dispatcher()) {
awaitEvent<Long> { handler ->
vertx.setTimer(1000, handler)
}
println("Event fired from timer")
}
- awaitEvent
The awaitEvent function suspends the execution of the coroutine until the timer fires and returns the value that was given to the handler
awaitEvent方法暂停执行协程,直到定时器返回结果给handler
标准的vert.x timerAPI是异步的,且逻辑也是写在回调Handler里的,所以代码看起来会是嵌套的,
但是上面的coroutines例子你会发现没有这个问题,所有的逻辑都是在变量timerId后面,
也就是说逻辑是线性的,直觉符合人类的思考方式,你会觉得上面的会阻塞1秒下面才会执行。
还需要想办法把vert.x的回调型API改成同步的,所以这里你会看到一个新的方法awaitEvent,
通过这个方法可以把handler(异步回调)以协程的方式进行处理,从而可以直接得到一个返回值,使之变成同步返回
awaitResult
vertx 中存在很多这种Handler< AsynResult<…>>
可以通过awaitResult 绑定该种类型的handler,以顺序的方式获取异步代码的执行结果launch or suspend
可以通过这两种方式在代码中使用协程,如下:
/**
*awaitResult方法暂停执行协程,直到定时器返回结果给handler
*/
suspend fun awaitResultExample(){
val eb = vertx.eventBus()
//注册消息的监听
val message : MessageConsumer<String> = eb.consumer<String>("com.sdmjhca")
message.handler { message ->
println("msg received : ${message.body()}"+System.currentTimeMillis())
message.reply("地瓜,你好,收到")
}
//开始发送消息,等待响应
val res = awaitResult<Message<String>> { handler ->
println(Thread.currentThread().name+"开始发送消息")
//eb.send("com.sdmjhca","土豆,你好,收到请回复")
//调用eb发送消息,并将发送的结果,付给handler
eb.send("com.sdmjhca","土豆,你好,收到请回复",handler)
}
println("收到土豆的回复 : ${res.body()}"+System.currentTimeMillis())
}
--------------------------------------
/**
* process one-shot event
* Calling launch allows running Vert.x handlers on a coroutine
* with no suspend
*/
fun awaitEventExample(){
launch(vertx.dispatcher()){
var timerId = awaitEvent<Long> { h: Handler<Long> ->
vertx.setTimer(1000,h)
println("定时器将在1秒后执行="+System.currentTimeMillis())
}
println("定时器执行完成Event fired from timer with id $timerId -------------"+System.currentTimeMillis())
}
}
vertx 相关代码的demo : https://github.com/sdmjhca/demo