【RubyConf 2021】 Async gem

Ruby 打開非同步大門的金鑰!

William
WilliamDesk
5 min readNov 12, 2021

--

這是在 RubyConf 2021 聽到的一場演講,是我有興趣的主題之一,因此把這場演講的內容翻譯成中文。

這是主講者bruno的github:https://github.com/bruno-

是很早期就致力於 Ruby 非同步併發到開發者。以下會圍繞這個 gem async 為主軸來講Ruby實現了併發非同步的處理。

這個gem的作者是 Samuel Williams,是Ruby 語言核心開發者之一,因此這個併發非同步的gem在公布出來後,立即獲得了蠻大的迴響。

今年在 RubyConf TW 也有邀請到Samuel Williams 來做該主題的演講,相關的共筆網址在這:https://hackmd.io/@coscup/r1jH7TPRO/%2F%40coscup%2FByCM7TDRO

因為Ruby在2.0時代,一直都是個非常標準的 同步程式語言(Synchronous programming language),在執行時會由第一行開始執行,直到最後一行結束。

但現在不一樣了,Ruby要有非同步的機制了!

要講非同步機制,我們要先從 javascript 看起:

雖然先執行了 fetch ,但因為要等待response,因此並沒有因為等待而讓整體主程式停滯,而是繼續往後執行下去,而等到fetch的回應回來後,再繼續進行該block要做的事情。

因此,如果多個fetch的形況呢?答案會是逼近 2 秒鐘。

再來看看 Ruby 執行類似的事情會花多少時間呢?答案是6秒鐘,因為Ruby並沒有async的機制。要執行第三行時,就必須等待第二行的response 2秒後回應才會執行。

所以得到結論:

當想要一樣的硬體配備,但能服務更多的請求;又或者當想要同時間API能處理更多的請求,我們需要async的機制。

why async? performance.

早期的Ruby實現async機制的做法:透過 threads

Ruby透過threads的確能實現async的機制,但也有非常多的缺點:

1. Thread之間容易產生 Race condition
2. Thread 的數量是有限制的,頂多只能操控數千個。

以下是一個簡單操作 Thread 來達到async的方式:

Async Ruby

作者提到了目前Ruby實作async時的四種作法:

1. Processes
2. Ractors, ruby actors,是Ruby 3.20的feature,尚未release。
3. Threads
4. Async

Async 的優秀的點在於他能非常輕易的擴展,以下舉幾個基於 Async 而擴展出去實踐不同服務非同步機制的gem。
1. async-http (a featureful HTTP client)
2. async-await (syntax sugar for Async)
3. falcon (HTTP server built around Async core)
4. async-redis (Redis client)
5. async-websocket

如果上面的例子改寫成使用async的ruby,會長得如何呢?

所有需要 Async 的執行內容會包在 block裡面,像這樣的形式:

除此之外,Async搭配其他原本慣用的method或慣用的套件時,也能完美的結合

例如我們用原本的 URI 的方式以及 HTTParty 來執行開啟網頁:

再來另外一個例子,展現Async與其他套件method的搭配是完全沒有問題的。

採async執行其他不同服務

此外作者在影片裡也在 Async 的 block 分別加了10次~100次的 iteration 重複執行這些已async的服務,在100次的 iteration 執行完的時間約為 3.75 秒。是可接受的結果,因為還有一些例如網路延遲等狀況需要考量進去。

實踐async的三大概念

1. Event reactor
2. Fibers
3. Fiber scheduler

  • Event reactor

這是所有程式語言實踐 async 的基礎。在Ruby 是以 nio4r這個 libev wrapper做基礎實踐。它有點類似 linux 的 epoll 機制、或是 mac 上的 kqueue,有著高效率使用資源以及擴展性高的特色。主要作為底層 I/O 事件的通知 (I/O event notifications)。

  • Fibers

你的程式碼會 順序式(sequentially)的執行在 task block;而task 在使用 'task.async {}’時執行 非同步式(asynchronously)的處理。

  • Fiber scheduler

這是 ruby 3.0 裡重要發表的一項 feature,用來調節 fibers的機制。

重要問題1: async 目前支援 Ruby on Rails 嗎?

目前不行 (2021/11/13)

因為 ActiveRecord 目前不支援 Async gem,還有許多需要調整的地方。但如果不涉及 ActiveRecord 的部分,仍然可以在Rails的框架中使用。

重要問題2: 目前 Async gem 在 ruby 已經正式發佈了嗎?

是,Async gem 經過了漫長且秘密開發期,目前已經發布了穩定正式版本,也開始有一些企業正在使用了。

--

--