源文檔
[很有趣的一個庫妖胀,一并翻譯了芥颈。]
本文依照 知識共享許可協(xié)議(署名-非商業(yè)性使用-禁止演繹) 發(fā)布。
Vertx-sync 是一組工具集赚抡,其特點是在不阻塞內核線程的同時爬坑,允許用戶以同步的方式接收事件、執(zhí)行異步操作涂臣。
簡介
比起很多歷史遺留的程序庫盾计,Vert.x的一個關鍵優(yōu)點是完全非阻塞(于內核線程而言)--這使它用少量的內核線程就可以處理大量的并發(fā)(例如,很多的連接赁遗、消息之類)署辉,具有良好的可擴展性。
Vert.x非阻塞性的結果是異步的API 岩四。異步API 可以有多種風格哭尝,包括像回調、promise剖煌、Rx(Java的風格)材鹦。Vert.x在絕大多數地方使用回調(盡管它也支持Rx)逝淹。
某些情況下,使用異步API 編程比起直接使用同步API 要更具挑戰(zhàn)桶唐,特別是當你有好幾個操作要按順序完成時栅葡。同時,使用異步API 時莽红,錯誤的傳遞也會變得更復雜妥畏。
Vertx-sync 可以讓你在熟悉的同步風格下繼續(xù)使用異步API 。
在此安吁,通往自由之路的功臣乃fiber
(這個詞國內有譯作纖程醉蚁,類似協(xié)程-coroutine)。Fiber 是超輕量級的線程鬼店,并不是對應于底層的那種內核線程网棍,它們被阻塞時不會導致內核線程也被阻塞。
Vert.x 借助Quasar 庫來實現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)的技術實現了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>>
作為最后的參數潮梯。例如用Vert.x 的 Mongo 客戶端執(zhí)行一次查詢或者發(fā)送一個event bus 消息然后拿到回應骗灶。
Vertx-sync 可以讓你用同步的方式拿到這種一次性的異步操作的結果。
這是通過調用Sync.awaitResult 方法達成的秉馏。
運行這個方法時耙旦,需將想要執(zhí)行的異步操作以Consumer的形式指定為其參數;handler 參數會在運行時傳給此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 會一直被阻塞住绕娘;而內核線程不會脓规。
獲得一次性的事件
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 使你能以同步的方式從這種流中接收事件臭笆。
你需要一個同時實現了Handler 和Receiver接口的HandlerReceiverAdaptor 類實例。Sync.streamAdaptor 方法可以創(chuàng)建這樣一個實例秤掌。
你可以把它當成一個普通的handler 愁铺,然后可以用實現自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 的用法(官方示例簡單明了似将,不妨一覽)。