本文へスキップ
BecomeCoder
ブログ一覧Wikiコース一覧

goroutineとは?Goの並行処理を初心者向けに|goとchannelの使い方

#Go#golang#goroutine#channel#並行処理

結論:goroutine(ゴルーチン)とは「関数の前に go を付けるだけで、その処理を別の流れで同時に走らせる仕組み」です。 そして同時に走る処理どうしが安全に値を受け渡す通り道が channel(チャネル)。この2つが Go の並行処理のほぼすべてで、どちらもブラウザ上で実際に動かして確かめられます。

「並行処理」と聞くと難しそうですが、Go は他の言語よりずっと少ない道具で書けるように設計されています。この記事では go キーワードと channel の使い方を、順番に手を動かしながら理解します。

goroutineとは ― go を付けるだけで同時に走る

普通のプログラムは、上から下へ1行ずつ順番に実行されます。これを「逐次(ちくじ)実行」と呼びます。それに対して goroutine は、ある処理を「別の流れ」で同時に走らせる ための単位です。

書き方はとても簡単で、関数呼び出しの前に go を付けるだけです。

go task("A") // task("A") を別の流れで実行(すぐ次の行へ進む)
task("B")    // こちらは通常どおり実行

go task("A") と書くと、maintask("A") の完了を待たずにすぐ次の行へ進みます。その結果、AB の処理が入り混じって進みます。これが並行処理の入り口です。

goroutine の強みは とても軽い こと。OS のスレッドより小さく、数千個作ってもびくともしません。だから Go は「たくさんの仕事を同時にさばくサーバー」の用途で広く使われています。

この goroutine の考え方は、Goコースの「goroutine ― 処理を同時に走らせる」レッスン でコード付きで解説しています(このレッスンは読み物です)。go を付ける/外すで出力の順番がどう変わるかを、次のレッスンから ブラウザでそのまま実行 して確かめられます(無料・登録不要)。

channelの使い方 ― goroutine 間で値を受け渡す

goroutine は別々に走るので、「その処理の結果をどう受け取るか」が次の問題になります。そこで登場するのが channel(チャネル) です。Go には「メモリを共有して通信するな、通信してメモリを共有せよ」という有名な合言葉があり、その「通信」を担うのが channel です。

ch := make(chan string) // string を運ぶチャネルを作る

go func() {
    ch <- "計算おわり" // チャネルに値を送る
}()

msg := <-ch // チャネルから値を受け取る(届くまで待つ)

矢印の向きがポイントです。

そして重要なのが、受け取り側は値が届くまで自動的に待つ こと。この「待ち合わせ」が、そのまま同期(タイミングを合わせること)の役割を果たします。「たぶんもう終わっただろう」と適当に待つ必要がなくなるのです。

goroutine ch <- 値 main <-ch で待つ channel(通り道)

このコードは Goコースの「channel ― goroutine 間で値を受け渡す」レッスンブラウザ上でそのまま実行 できます。値の送受信を自分で書き換えて、待ち合わせが起きる様子を体感してみてください。

複数の goroutine を待つ ― WaitGroup と select

goroutine が1つなら channel の受信で待てますが、実務では「たくさん起動して、全部終わったら次へ」という場面が普通です。そのための道具が2つあります。

Goコースの並行処理は、最初の goroutine レッスン(読み物)を除き、channel・WaitGroup・select の回をすべてブラウザ内の実行環境で動かせます。環境構築なしで、go run の代わりに実行ボタンを押すだけです。

つまずきやすいところ

初心者が並行処理で最初にぶつかるのは、次の2つです。

なお、並行処理に限らず Go でよく出るエラーの読み方は Goのエラー逆引き にまとめてあります。エラーメッセージが出て手が止まったら、まずここで検索してみてください。

次に読む

← ブログ一覧に戻る