つくる: 並行集計
カテゴリごとに同時に数える
第7章の内容を全部使います。
プレーンテキスト
ゴルーチン go で走らせる
チャネル 結果を受け取る
WaitGroup 完了を待つ
Mutex 共有する変数を守る作るのは、カテゴリ別の売上集計です。カテゴリごとに1つのゴルーチンを立てて、同時に計算します。
プレーンテキスト
本:2000 家電:248003つの書き方から選ぶ
並行に集計して結果をまとめる方法は、いくつかあります。
プレーンテキスト
1. チャネルで受け取る 入れた数だけ取り出す
2. スライスの別の場所に書く 衝突しないので Mutex 不要
3. マップを Mutex で守る 共有するので保護が要る2番がいちばん素直です。 カテゴリの一覧を先に作っておけば、それぞれの結果を別の添字に書けます。共有する変数が無いので、Mutex も要りません。
第7章で「まず分けるか渡すかを考える」と書いたのは、こういう場面のことです。
順番を保つ
マップを使うと、出力の順番が毎回変わります。第5章でやったとおりです。
この演習ではカテゴリの登場順に並べてもらいます。スライスで順番を持てば、並行に計算しても順番は崩れません。ここも2番の書き方が効く理由です。
手順
プレーンテキスト
1. カテゴリの一覧を、登場順に重複なく集める
2. 一覧の長さぶんの結果スライスを用意する
3. カテゴリごとにゴルーチンを立て、合計を該当の添字へ書く
4. WaitGroup で全部待つ
5. 一覧の順に文字列を組み立てる1 は並行処理ではありません。先に順番を確定させてから並行に走らせる、という段取りです。ここを並行にすると順番が崩れます。
引数で渡すのを忘れない
Go
go func(idx int, cat string) {
defer wg.Done()
results[idx] = sumOf(cat)
}(i, category)ループの変数をそのまま参照せず、引数で渡します。第4章の defer と同じ理由で、始めた時点の値を使うためです。
要件
- カテゴリを登場順に重複なく集める
- カテゴリごとにゴルーチンを立てて合計を計算する
sync.WaitGroupで全部の完了を待つカテゴリ:合計を半角スペース区切りで、登場順に並べる- 0件のときは空文字を返す
入出力例
categoryTotals(["本","家電","本"], [1200,24800,800]) → "本:2000 家電:24800"
categoryTotals(["本","本"], [1000,2000]) → "本:3000"
categoryTotals(["家電","本","家電"], [500,100,500]) → "家電:1000 本:100"
categoryTotals(["A","B","C"], [10,20,30]) → "A:10 B:20 C:30"ヒント
編集 ゆめさく編集部