goroutineの使いどころ

Shinichi Jufuku
Eureka Engineering
Published in
5 min readDec 4, 2019

この記事は eureka Advent Calendar 2019 4日目の記事です。

今回、goroutine最大のパフォーマンスを引き出すために、goroutineの使いどころについて考えてみました。

並行処理するとどのくらいメリットがあるの?

この疑問を解決するのがアムダールの法則という並列化により期待できる性能向上を表した数式になります。

Credit:ja.wikipedia.org

数式だと難しいので、オライリーのGo言語による並行処理で書かれている説明を見てみます。

そのプログラムの何割を並列化できないかによって、並列化による性能向上の限界が決まる

これを少し言い換えてみると、並列化できない処理=(逐次的に実行しなければならない部分)の時間が、並行処理でのパフォーマンスの限界という事になります。

この並列化と性能向上を表した式がこちらです。

図で表現したものがこちらです。

Credit:ja.wikipedia.org

プログラムのほとんどが並列実行できる場合は、プロセッサ数に比例して性能が向上していきますが、プログラムの半分(0.5)が並列実行できない場合は、理論上の性能向上限界は最大でも2倍であることを表しています。

※プログラムの半分(0.5)が並列実行できない時に、プロセッサ数を1000で計算すると性能向上率は1.998002倍となります。

では、goroutineの使いどころって?

goroutineを説明する前にまず、並列処理の仕組みをざっと振り返ります。

CPUが並列処理を実行する為のマルチコア・マルチスレッド、Webサーバーが並列処理を実行する為のマルチプロセス、マルチスレッド、イベント駆動、Go言語が並列処理を実行する為のGoランタイムが管理するgoroutine、これら全ては仮想的に並列処理を行う仕組みであり、その仕組みには必ずオーバーヘッドが存在します。

オーバーヘッドがあるのになぜgoroutineはC10K問題を解決するとまで言われているのでしょう?(※C10K問題=クライアント1万台問題)

その理由を分かりやすく説明をしているサイトは様々ありますが、今回参考にさせて頂いたサイトのリンクを掲載しておきますので、詳しく知りたい方は是非ご覧ください。

今回細かい説明は割愛しますが、goroutineの特徴を端的に言うと下記の2つです。

・スレッドに比べてメモリ使用量が少ない

・スイッチングコスト(オーバーヘッド)が低い

結果、goroutineはマルチスレッドに処理を任せるより圧倒的なパフォーマンスで並列処理を実行する事ができるのです。

ここで少し余談ですが、goroutineを増やしても処理速度が上がるとは限らないと言う話を良く聞きます。

私はその原因はいくつかあると考えており、まず1つめにGOMAXPROCSで利用CPUコア数を増やした際、goroutineの並列数がある一定の数を超えるとOSのマルチスレッドが利用され始めそちらのオーバーヘッドに引っ張られ処理が遅くなるというパターン。これはgoroutineを増やしていくと処理が遅くなりましたというベンチマーク記事がまさにその現象だと思います。(この辺り、もし詳しい解説あれば見てみたい…)

もう1つは、並列化する処理よりもgoroutineのスイッチングコストの方が大きくなるパターン。これは例えばfor文の中の単純な処理をgoroutineで回してしまった場合、for文で順次処理するよりもgoroutineのスイッチングコストに時間がかかり処理が遅くなってしまいます。

以上を踏まえると、goroutineの使いどころとしては

・CPUのMAXコア数で、並列実行できる割合が大きい処理をどれだけ並列実行できるか

がポイントとなってきそうです。

今回はここまでとなります。次回は具体的なベンチマークと合わせていくつかの並行処理パターンをご紹介できればと思います。

最後までお読みいただきありがとうございました。

--

--