源文檔
[很有趣的一個庫,一并翻譯了。]
本文依照 知識共享許可協(xié)議(署名-非商業(yè)性使用-禁止演繹) 發(fā)布。
Vertx-sync 是一組工具集,其特點是在不阻塞內(nèi)核線程的同時,允許用戶以同步的方式接收事件、執(zhí)行異步操作。
簡介
比起很多歷史遺留的程序庫,Vert.x的一個關鍵優(yōu)點是完全非阻塞(于內(nèi)核線程而言)--這使它用少量的內(nèi)核線程就可以處理大量的并發(fā)(例如,很多的連接、消息之類),具有良好的可擴展性。
Vert.x非阻塞性的結果是異步的API 。異步API 可以有多種風格,包括像回調(diào)、promise、Rx(Java的風格)。Vert.x在絕大多數(shù)地方使用回調(diào)(盡管它也支持Rx)。
某些情況下,使用異步API 編程比起直接使用同步API 要更具挑戰(zhàn),特別是當你有好幾個操作要按順序完成時。同時,使用異步API 時,錯誤的傳遞也會變得更復雜。
Vertx-sync 可以讓你在熟悉的同步風格下繼續(xù)使用異步API 。
在此,通往自由之路的功臣乃fiber(這個詞國內(nèi)有譯作纖程,類似協(xié)程-coroutine)。Fiber 是超輕量級的線程,并不是對應于底層的那種內(nèi)核線程,它們被阻塞時不會導致內(nèi)核線程也被阻塞。
Vert.x 借助Quasar 庫來實現(xiàn)fiber 。
注意:Vertx-sync 當前只適用于Java 。
SyncVerticle
要使用Vertx-sync 庫,你的代碼需要繼承io.vertx.ext.sync.SyncVerticle類,并重載start()方法和stop()方法(stop 非必需)。
這些方法還必須加上@Suspendable的標注。
寫好的sync verticle,其部署方法和其他verticle完全一樣。
Instrumentation
Vert.x用到了Quasar 庫,這個庫借助字節(jié)碼增強(bytecode instrumentation)的技術實現(xiàn)了fiber 。(字節(jié)碼增強的)工作是在運行時(run-time)由java agent 完成的。
要使這個特性正常工作,需要在啟動JVM 時指定quasar-core jar包為java agent jar包:
-javaagent:/path/to/quasar/core/quasar-core.jar
如果你用的是vertx命令行工具,可以在執(zhí)行vertx前設置環(huán)境變量ENABLE_VERTX_SYNC_AGENT為ture,這樣可以啟用agent 的配置。
你也可以使用quasar-maven-plugin 達成離線增強(a offline instrumentation, 指非運行時織入字節(jié)碼)的效果。更多細節(jié)請參考 Quasar documentation 。
獲得一次性的異步操作結果
Vert.x 的領域里,很多操作都會接受一個Handler<AsyncResult<T>>作為最后的參數(shù)。例如用Vert.x 的 Mongo 客戶端執(zhí)行一次查詢或者發(fā)送一個event bus 消息然后拿到回應。
Vertx-sync 可以讓你用同步的方式拿到這種一次性的異步操作的結果。
這是通過調(diào)用Sync.awaitResult 方法達成的。
運行這個方法時,需將想要執(zhí)行的異步操作以Consumer的形式指定為其參數(shù);handler 參數(shù)會在運行時傳給此consumer 。
看下面的例子:
EventBus eb = vertx.eventBus();
// Send a message and get the reply synchronously
Message<String> reply = awaitResult(h -> eb.send("someaddress", "ping", h));
System.out.println("Received reply " + reply.body());
上面的例子中,在回應返回前,fiber 會一直被阻塞??;而內(nèi)核線程不會。
獲得一次性的事件
Vertx-sync 也能以同步的方式獲得一次性的事件,例如定時器的觸發(fā),或者end handler(關于end handler 的例子可以參見Vert.x 核心包文檔中 HTTP 服務器與客戶端 一節(jié)) 的執(zhí)行。這是通過Sync.awaitEvent 方法達成的。
看下面的例子:
long tid = awaitEvent(h -> vertx.setTimer(1000, h));
System.out.println("Timer has now fired");
事件流
很多時候,Vert.x 的handler 接收到的是事件流,例如event bus 消息的消費者(consumer)、HTTP 服務器里的HTTP 服務端請求(server request)。
Vertx-sync 使你能以同步的方式從這種流中接收事件。
你需要一個同時實現(xiàn)了Handler 和Receiver接口的HandlerReceiverAdaptor 類實例。Sync.streamAdaptor 方法可以創(chuàng)建這樣一個實例。
你可以把它當成一個普通的handler ,然后可以用實現(xiàn)自Receiver 接口的方法來同步地接收事件。
下面是一個 event bus 消息消費者的例子:
EventBus eb = vertx.eventBus();
HandlerReceiverAdaptor<Message<String>> adaptor = streamAdaptor();
eb.<String>consumer("some-address").handler(adaptor);
// Receive 10 messages from the consumer:
for (int i = 0; i < 10; i++) {
Message<String> received1 = adaptor.receive();
System.out.println("got message: " + received1.body());
}
使用FiberHandler
如果你想在一般的handler 中使用fiber --例如Http 服務器的請求handler ,那得首先把這個一般的handler 轉換為fiber handler 。
Fiber handler 會在fiber 里運行那個一般的handler 。
看例子:
EventBus eb = vertx.eventBus();
vertx.createHttpServer().requestHandler(fiberHandler(req -> {
// Send a message to address and wait for a reply
Message<String> reply = awaitResult(h -> eb.send("some-address", "blah", h));
System.out.println("Got reply: " + reply.body());
// Now end the response
req.response().end("blah");
})).listen(8080, "localhost");
更多示例
在examples repository 這里有一打示例,展示了vertx-sync 的用法(官方示例簡單明了,不妨一覽)。