GVL が外れる ruby のメソッドはどれですか？


ruby でマルチスレッドプログラミングを行う場合、どの ruby のメソッドが GVL
を外すのかを意識することが重要になります。というのも、それがないと、マルチスレッド環境で実装したとしても、処理が平行して実行されないからです。

自分の理解としては、以下の ruby のメソッドたちは、 GVL が外れると理解しています。

  * `Kernel#sleep`
  * `IO#read`, `IO#write`

ふと、マルチスレッド環境で `system` 系のコマンド実行を実装しようとして、これは GVL 的に大丈夫なのだろうか、と疑問に思いました。

### 質問

  * ruby のメソッドの中で、 GVL が外れるものはどれですか？ 
    * 例えば、(ないとは思いますが)ありとあらゆるシステムコールに対して GVL が外れたりしますか？




Cレベルでは`rb_thread_call_without_gvl`または`rb_thread_call_without_gvl2`(違いはinterruptのありなし)を呼び出すことでGVLを外したスレッドで実行されることになります。逆に言うとこの二つの関数を呼び出しているところでは一時的にGVLが外れた処理がされていると言うことです。

2.6系のソースを軽く見た程度ですが、次のような所で上の関数が呼ばれていました。

  * Bignumの商・剰余
  * Dir.new/Dir.open
  * Dir.chdir
  * Dir.rmdir
  * Dir.empty?
  * Dir.glob
  * File.chown
  * Fileのstatといったファイルの状態を見に行く多くのメソッド
  * File.rename
  * File.truncate
  * File.mkfifo
  * IO.copy_stream
  * IO.#openおよびIO#closeに関わるほぼ全て？(ちょっと全ては追い切れなかった)
  * Kernel.#system
  * Kernel.#exec 

他にも標準ライブラリではfiddle, openssl, readline, socket, zlibで使用されています。

IO周りはopen時にGVLを外している場合があるようです。read/writeの処理がどうなのかはそこまで詳しくないのでよくわかりませんでした。

全てを確認したわけではありません。これ以外にも内部で上のメソッド呼び出している場合があります。また、メソッドの全ての処理についてGVLが外れるのではなく、処理の一部でGVLが外れることになります。環境や処理内容によっては外れないままの場合もあります。

なお、Kenrel.#sleepはスレッド処理の一部として組み込まれているようです。

* * *

GVLが外れた場合の恩恵を受けるのはマルチコアな環境です。シングルコアな環境ではGVLが外れても処理全体の速度が向上するわけではありません。通常の処理のほとんどでGVLを外すことは(CRubyの実装上)不可能なので、IO処理や余程重いライブラリ処理のみでGVLを外しているようです。マルチコアをフルに使いたいというのであれば、マルチフォークにしたほうが良いでしょう。マルチスレッドのままマルチコアをフルに使いたいというのであれば、JRubyを検討した方が良いでしょう。




Cレベルでは`rb_thread_call_without_gvl`または`rb_thread_call_without_gvl2`(違いはinterruptのありなし)を呼び出すことでGVLを外したスレッドで実行されることになります。逆に言うとこの二つの関数を呼び出しているところでは一時的にGVLが外れた処理がされていると言うことです。

2.6系のソースを軽く見た程度ですが、次のような所で上の関数が呼ばれていました。

  * Bignumの商・剰余
  * Dir.new/Dir.open
  * Dir.chdir
  * Dir.rmdir
  * Dir.empty?
  * Dir.glob
  * File.chown
  * Fileのstatといったファイルの状態を見に行く多くのメソッド
  * File.rename
  * File.truncate
  * File.mkfifo
  * IO.copy_stream
  * IO.#openおよびIO#closeに関わるほぼ全て？(ちょっと全ては追い切れなかった)
  * Kernel.#system
  * Kernel.#exec 

他にも標準ライブラリではfiddle, openssl, readline, socket, zlibで使用されています。

IO周りはopen時にGVLを外している場合があるようです。read/writeの処理がどうなのかはそこまで詳しくないのでよくわかりませんでした。

全てを確認したわけではありません。これ以外にも内部で上のメソッド呼び出している場合があります。また、メソッドの全ての処理についてGVLが外れるのではなく、処理の一部でGVLが外れることになります。環境や処理内容によっては外れないままの場合もあります。

なお、Kenrel.#sleepはスレッド処理の一部として組み込まれているようです。

* * *

GVLが外れた場合の恩恵を受けるのはマルチコアな環境です。シングルコアな環境ではGVLが外れても処理全体の速度が向上するわけではありません。通常の処理のほとんどでGVLを外すことは(CRubyの実装上)不可能なので、IO処理や余程重いライブラリ処理のみでGVLを外しているようです。マルチコアをフルに使いたいというのであれば、マルチフォークにしたほうが良いでしょう。マルチスレッドのままマルチコアをフルに使いたいというのであれば、JRubyを検討した方が良いでしょう。

