Go PR

Go言語で並行処理プログラミング入門から実践まで -goroutineとchannelのチュートリアルあり-

Go言語で並行処理プログラミング
記事内に商品プロモーションを含む場合があります

こんにちは。

現役エンジニアの”はやぶさ”@Cpp_Learningです。最近はGo言語で色々やってます。

今回はgoroutine(ゴルーチン)とchannelを使った並行処理プログラミングについて勉強したので、備忘録も兼ねて本記事を書きます。

なお本記事の【文章構成】は以下の通りなので、ソースコードだけ見せて!という人は、目次から『実践!Go言語で並行処理プログラミング』に飛んで実践編から読み進めて下さい。

文章構成
  • 入門編:Go言語と並行処理プログラミングの基礎
  • 実践編:並行処理プログラミングの実践チュートリアル

並行処理と並列処理の違い

並行(Concurrency)と並列(Parallelism)は以下のように区別できます。

In programming, concurrency is the composition of independently executing processes, while parallelism is the simultaneous execution of (possibly related) computations. Concurrency is about dealing with lots of things at once. Parallelism is about doing lots of things at once.

Concurrency is not parallelism|The Go Blog

私なりの解釈は以下の通りです。

【並行処理】

独立している複数のタスクを同時に処理すること

【並列処理】

関連のある複数のタスクを同時に処理すること

例えば、マウスとキーボードを使ってブログを書くのは並行処理、行列演算は並列処理と考えています。

並行処理デザイン

並行処理のデザイン(設計)については、この資料が非常に分かりやすいです。

この資料を一部引用し、かつ私の解釈も加えて並行処理デザインのヒントを解説します。

本の山を焼却する仕事があるとします。この仕事をgopher(ゴーファー君)一匹でやるのは大変時間がかかります。

Go言語で並行処理プログラミング

同じ仕事を二匹のgopher(ゴーファー君)でやれば、二倍速で仕事が終わります。

Go言語で並行処理プログラミング

しかし、入力される本の量が少なくて、gopher(ゴーファー君)一匹で運べる場合、上記のデザインは、最初に示した非効率なデザインと等しくなります

そこで仕事を「本をカートに積む」・「本を運ぶ」・「焼却する」に分割し、三匹のgopher(ゴーファー君)にやってもらいます。

Go言語で並行処理プログラミング

最初に比べて効率的になりましたが、三匹のgopher(ゴーファー君)が独立して(同時に)働くため、どこかで手待ちが発生しそうです。

そのため、より仕事を分割できないか検討し「空のカートを戻す」を追加して、四匹のgopher(ゴーファー君)にやってもらいます。

Go言語で並行処理プログラミング

このように仕事を最小単位に分割し、複数のgopher(ゴーファー君)にやってもらうのが、スマートな並行処理デザインです。

引用元:Concurrency is not Parallelism

はやぶさ
はやぶさ
引用元の資料が素晴らしいので、是非読んでほしいです
スポンサーリンク

Go言語と並行処理プログラミング

Go言語は非同期処理が得意なプログラミング言語です。

具体的にはgoroutine(軽量なスレッド)を活用したスマートな非同期処理ができます(下図のゴーファー君をgoroutine実行と考えてもOK)。

Go言語で並行処理プログラミング

引用元:Concurrency is not Parallelism

またchannelを活用すれば、goroutine間の通信ができるため、スレッドセーフな並行処理もできます。

Go言語で並行処理プログラミング

引用元:Go Concurrency Patterns

簡単にまとめると以下の通りです。

Go言語による並行処理プログラミング概要
  • goroutineによるスマートな非同期処理
  • メモリ消費量が少ない
  • channelによる安全な排他制御
  • 標準パッケージのみで実現
  • シンプルなコードでスッキリ書ける

goroutineとchannelの基本的な使い方

Go言語を勉強するなら、ハンズオン形式で学べるこのサイトがオススメです。goroutineとchannelの基本的な使い方も学べるので、是非やってみて下さい。

以上までの内容が【入門編】でした。

【入門編】の内容
  • 並行処理と並列の違い
  • 並行処理デザイン
  • Go言語と並行処理プログラミンの概要(前知識)
  • goroutineとchannelの基本的な使い方(おすすめのサイト紹介)

(入門編 完)

実践!Go言語で並行処理プログラミング

以降からは『goroutineとchannelによる並行処理の実践』をハンズオン形式で解説します。

課題

以下の記事と同じ課題をGo言語で実践します。

Cpp-Taskflow.jpg
【Cpp-Taskflow】C++で並列処理・マルチタスク -入門から実践まで-こんにちは。 現役エンジニアの”はやぶさ”@Cpp_Learningです。 C++でソフトウェア開発をしています。C++でプ...

つまり、以下のフローをGo言語で実現します。

C++で並列処理・マルチタスク

a = 6, b = 8, c = 0, d = 3, e = 9, f = 0, g = 0で初期化したときの結果は以下の通りです。

g = a × b ÷ (d + e)
g = 6 × 8 ÷ (3 + 9)
g = 48 ÷ 12
g = 4

※c = a × b, f = d + e とおき、並行処理することで高速化が見込めます

並行処理しないプログラミン

最初に並行処理しないソースコードを作成します。

いたって普通のソースコードです。

goroutineとchannelによる並行処理

先ほど作成したソースコードをgoroutineとchannelで並行処理するコードに改良します。

関数を呼ぶときに“go”を付けるだけでgoroutine(非同期)実行ができます。

また、“mult”と”add”より先に”divs”を実行すると困るので、channelを使っい、”ch1”と”ch2”を受信するまで待機させています。

Go言語で並行処理プログラミング

引用元:Go Concurrency Patterns

goroutine使う/使わないを柔軟に変更できるデザイン

演算処理とchannel処理を分離すれば、goroutine使う/使わないを柔軟に変更できるデザインになります。

例えば “go taskC” の部分を以下のように変更できます。

(実践編 完)

まとめ

本記事は以下の【文章構成】『Go言語で並行処理プログラミング入門から実践まで』を解説しました。

文章構成
  • 入門編:Go言語と並行処理プログラミングの基礎
  • 実践編:並行処理プログラミングの実践チュートリアル

channelを使わずに並行処理する方法もありますが、いくつ試してみてgoroutineとchannelを使うのがスマートだと感じました。

改めて、Go言語による並行処理プログラミングの概要を示します。

Go言語による並行処理プログラミング概要
  • goroutineによるスマートな非同期処理
  • メモリ消費量が少ない
  • channelによる安全な排他制御
  • 標準パッケージのみで実現
  • シンプルなコードでスッキリ書ける

C++のときは専用ライブラリを活用することで非同期のマルチスレッド処理を実現しましたが、Go言語だと標準パッケージのみで実現できました。

くるる
くるる
Go言語すげー
はやぶさ
はやぶさ
Go言語入門して以来、Go言語のことがどんどん好きになってます

今後もGoの記事を書く予定なので、情報共有をしながら、一緒に成長できると嬉しいです。

はやぶさ
はやぶさ
よろしくお願いします。

以下 Go言語の本紹介

PICK UP BOOKS

  • 数理モデル入門
    数理モデル
  • Jetoson Nano 超入門
    Jetoson Nano
  • 図解速習DEEP LEARNING
    DEEP LEARNING
  • Pythonによる因果分析
    Python