Goroutine の基本
CoddyのGOジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 59/107。
goroutineは、Goランタイムによって管理される軽量な実行スレッドです。大量のメモリを消費する従来のスレッドとは異なり、goroutineはわずか数キロバイトのスタック領域で開始されるため、何千ものgoroutineをconcurrently実行できます。
goroutine を開始するには、関数呼び出しの前に go keyword を置くだけです:
func sayHello(name string) {
fmt.Println("Hello,", name)
}
func main() {
go sayHello("Alice") // 並行して実行される
go sayHello("Bob") // 並行して実行される
time.Sleep(100 * time.Millisecond)
fmt.Println("Done")
}go sayHello("Alice") が実行されると、sayHello の完了を待ちません。代わりに、sayHello がバックグラウンドで実行されている間、すぐに次の行へ進みます。これが time.Sleep が必要な理由です。これがないと、main は goroutines が完了する前に終了してしまいます。
無名関数を使ってgoroutineをlaunchすることもできます。
go func(msg string) {
fmt.Println(msg)
}("Hello from goroutine")main function 自体は goroutine 内で実行されます。main function が戻ると、他の goroutines はすべて直ちに終了します。完了する機会はありません。time.Sleep の使用は一時的な解決策です。これからのレッスンでは、チャネルと wait groups を使った適切な同期手法を学びます。
チャレンジ
簡単goroutines を使用して複数のタスクを concurrently 実行する task runner を構築しましょう。main プログラムが継続して動作する間、タスクがバックグラウンドで実行されるシンプルなシステムを作成し、goroutines によって並行実行が可能になる仕組みを示します。
コードを2つのファイルに整理します。
tasks.go: タスク実行ロジックを Define します。Name(string)とDuration(int、milliseconds を representing)fields を持つTaskstruct を作成します。TaskにRun()method を Implement し、タスクの duration だけ sleep することで作業をシミュレートし、その後に次を Print します:Task [Name] completed各タスクの
Run()method を goroutine として launches するRunAllTasks(tasks []Task)function を作成します。すべての goroutines を Launch した After、完了できるように 500 milliseconds sleep し、その後に次を Print します:All tasks launchedmain.go: タスク情報を Read し、concurrent な実行を調整します。タスクの number を Read し、続いて各タスクの名前と duration を Read します。タスクを Create して
RunAllTasksに渡します。それが戻った After、次を Print します:Main function done
次の入力が提供されます。
- Line 1: タスクの number(integer)
- Following lines: 各タスクについて2行 — タスク名、続いて milliseconds 単位の duration
たとえば、次の入力が与えられた場合:
3
Download
100
Process
50
Upload
75出力には、タスクの完了(concurrency により順序は変わる場合があります)に続いて、完了メッセージが表示されます。
Task Process completed
Task Upload completed
Task Download completed
All tasks launched
Main function done注: goroutines は concurrently 実行されるため、duration が短いタスクは通常先に完了します。タスクの完了順序は duration に依存し、短いタスクが長いタスクより先に完了します。
遅延には time.Sleep、time.Duration、time.Millisecond を使用します。RunAllTasks 内の sleep がなければ、goroutines が作業を完了する前に function が戻ることを忘れないでください。
自分で試してみよう
package main
import (
"fmt"
)
func main() {
// タスクの数を読み取る
var numTasks int
fmt.Scanln(&numTasks)
// TODO: タスクを保持するスライスを作成する
// TODO: 各タスクの名前と所要時間を読み取る
// 各タスクについて:
// - タスク名を読み取る
// - 所要時間を読み取る(整数として)
// - Task を作成してスライスに追加する
// TODO: タスクのスライスを使って RunAllTasks を呼び出す
// TODO: Print "Main function done"
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
1Go オブジェクト指向の基礎
外部ファイルGo ワークスペースとモジュールパッケージとインポート公開された名前と非公開の名前Go におけるオブジェクト指向入門クラスとしての構造体構造体へのメソッド定義ポインタレシーバと値レシーバ構造体の初期化コンストラクタ関数まとめ:簡易計算機8エラー処理とOOP
error インターフェースカスタムエラー型エラーラッピング (fmt.Errorf)センチネルエラーerrors.Is() と errors.As()Panic、Defer、Recover復習 - ファイルパーサー自分で練習してみよう: Goオンラインコンパイラ