[筆記] Threads in Ruby

Ruby is Single-Threaded

Ruby’s thread is a user-level thread that is originally written. The characteristic of this implementation is a very high portability in both specification and implementation. Surprisingly a MS-DOS can run the thread. Furthermore, you can expect the same response in any environment. Many people mention that this point is the best feature of Ruby.
However, as a trade off for such an extremeness of portability, Ruby abandons the speed. It’s, say, probably the slowest of all user-level thread implementations in this world.

節錄自 Ruby Hacking Guide

Thread

Thread 是 program 的執行單位。在一個多核心(core)的裝置,作業系統可以將多個 thread 放在不同核心跑,提升整體表現速度。Thread 會儲存自己在 program 中的位置,所以可以很輕易地切換。Ruby 只會跑在一個 thread 中,所以不會有交換的時候(No switching of tasks taking place),也只會跑在一個核心中。但是如果今天是多核心的電腦,如下圖所示,我們要如何才能夠好好利用這個資源呢?

source: https://dev.to/enether/rubys-gil-in-a-nutshell

Ruby 有一個 Thread 類別,顧名思義它會幫我們創造一個 native thread 跑在作業系統裡。

不過當我們要使用 Thread 的時候,要記得當 main thread 結束了 program 就會結束,所以如果要確保 program 等到所有線程都跑完才結束,就要加上 ThreadsWait 類別(require ‘thwait’)並且在程式裡面宣告 ThreadsWait.all_waits(another_thread)

所以現在 Ruby 就可以跑在多個 thread 裡面了?不。Ruby 有一個 GIL (Global Interpreter Lock) 特性阻止這件美好事情的發生。

Ruby 的 Global Interpreter Lock

GIL (Global Interpreter Lock) 是一個 Ruby implementation 的特性,它會讓資料一次只能被一個 thread 存取。也就是說,它禁止 parallelism with shared memory(比如說同時存取同一個變數)。所以 another_thread 會在主要程序跑到它願意釋放 GIL(經由 Ruby Runtime)才被執行。誰有 GIL 誰就有 CPU 資源。在這個情況之下,使用 Thread 這個類別只會徒耗資源。

切換 thread 的過程叫做 Context Switching

為何會有 Global Interpreter Lock anyway? 因為它保障了 thread-safe的特性。Ruby 的官方 interpreter YARV (Yet Another Ruby VM)MRI (Matz’s Ruby Interpreter)有 GIL,但是不是所有 implementation 都有,比如說 JRubyIronRuby 就沒有。

所以說 Ruby 是一個 single-threaded 語言不是最精確的,應該是說 Ruby 的 implementation 是 single-threaded。

Thread Safety

OS context switch 是一個 involuntary context switch,它會被 kernel’s scheduler 安排,是不可避免也不可預期的。當 context switch 發生在一個式子賦值之前,比如在當 a = a + 1,正在進行到一半,也就是 a+1,但是還沒有把這個新的值賦予 a 時,context switching 就會讓 a 停留在原本的狀態,造成災難。

GIL 會在 OS context switch 發生時拒絕 interpreter 的存取,強制把 CPU 的控制權還給有 GIL 的 thread。所以 involuntary context switch 發生時只會讓速度慢下來,而不會破壞它。

GIL 的其他好處

  • 更快速的 single-threaded programs (MRI 的開發人員曾經嘗試過把 GIL 拿掉,用其他方式保護核心函式庫的 thread-safety,但結果發現這樣 single-threaded 的情況下速度會變很慢,所以放棄了)。
  • 使用 C 的函式庫更加容易,因為我們不需要考慮到 thread safety (這跟 MRI 的歷史有關,可以參考這篇文章)。
  • 讓 Garbage Collection 更簡單。

雖然已盡能力所及地確保資料的正確性,但我恐怕還是會有不對/不精確的觀念或用字,如果願意指正我的話我會非常感激!

參考資料

Ruby's GIL in a nutshell
dev.to
Confused, are languages like python, ruby single threaded? unlike say java? (for web apps)
stackoverflow.com
More about MRI and the GIL
www.jstorimer.com

文章同步發表於 Medium


  • Find me at