vertx框架編程思想

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章