この記事は、Go3 Advent Calendar 2018 の11日目の記事です。
##はじめに
Goにはgoroutineという並行処理を簡単に実行できる機能があります。
goroutineは「goroutineとは軽量スレッドである」と説明されていますが、結局goroutineとスレッドって何が違うのかということを調べてみました。
まず最初に言うとgoroutineの実体はスレッドです。
ですが大きく3つの違いがあります。順番に見ていきましょう。
##メモリ消費量
スレッドのデフォルトスタックサイズは Windows だと 1 MB、Linux だと 2 MB で
goroutineは数キロバイトで済みます。
必要に応じてヒープ領域を割り当てたり開放したりします。一方でスレッドはスレッド間のメモリが干渉し合わないように「スタックガードページ」と呼ばれる 1Mbの領域の確保から始めます。
数キロバイトで済む goroutine に比べると、10 KB だとしても100〜200倍の違いがあります。
##生成と破棄に要する時間
スレッドは生成と破棄のたびに OS に要求を投げて、それが完了して返ってくるのを待つため時間がかかります。
一方で goroutine では、生成と破棄に関する操作を非常に低コストで行うことができます。
##スイッチングに要する時間
スレッドがブロックされると、別のスレッドがスケジューリングされます。 プリエンプティブ方式でスレッドがスケジューリングされ、スレッドの実行がスイッチされる際にスケジューラーは全てのレジスタ、つまり 16種類の汎用レジスタ、PC(プログラムカウンタ)、SP(スタックポインタ)、16種類の XMM レジスタ、 FP co-processor の状態、16種類の AVX レジスタ、そしてモデル固有のレジスタを別の場所に保存したり、保存したそれらをレジスタに戻す処理が必要になります。これはスレッド間で迅速にスイッチングしたい場合に、無視できません。
goroutine は協調してスケジューリングされ、スイッチングが発生したときも、たった 3つのレジスタ(PC、SP、DX)しか保存したり、レジスタに戻したりしません
##まとめ
Goは並行処理をするにあたってgoroutineを使うことによってメモリ消費量を抑えてました。
メモリ使用量が多くなり過ぎると、スワップが発生し性能低下を招くため、小さなメモリ使用量で済むというのは大きな利点だと思います。
ここで述べた以外にもgoroutineはスレッドよりも起動時間が早かったり、メモリ消費量がすくないためスレッドに比べてもより多く
の並行処理を実行することができるとも言われています。(他にも利点は色々とある)
並行処理が簡単に実行できて、スレッドよりも数多くの並行処理を実行できるgoroutineという機能があるGoは最高ですね。
(気付いた点等ございましたら、お知らせください)