2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

goroutineで大食い大会

2
Last updated at Posted at 2019-08-27

はじめに

ゴルーチンとチャネルの勉強として大食い大会を書いてみた。

1)コックはひたすらホットドッグを作る
2)ウェイターはひたすらホットドッグをフードファイターへ運ぶ
3)フードファイターはひたすらホットドッグを食べて、自分が食べたホットドッグをカウントする
4)制限時間になったら大会終了。その時点でのランキングを出す。

この 1 => 2 => 3 の流れをチャネルを使い、4の制限時間の制御にcontextを使った。

コード


package main

import (
	"context"
	"fmt"
	"time"

	. "github.com/ahmetb/go-linq"
)

func cook(
	done <-chan interface{},
	fn func() interface{},
) <-chan interface{} {
	foods := make(chan interface{})
	go func() {
		defer close(foods)
		for {
			select {
			case <-done:
				return
			case foods <- fn():
			}
		}
	}()
	return foods
}

func hotDog() interface{} {
	fmt.Printf("コックはホットドッグを作ります\n")

	return "ホットドッグ"
}

func waiter(foods <-chan interface{}) interface{} {
	food := <-foods
	fmt.Printf("ウェイターは%vをフードファイターへ持っていきます。\n", food)
	return food
}

func waitperson(
	done <-chan interface{},
	foods <-chan interface{},
) <-chan interface{} {
	toFoodFighter := make(chan interface{})
	go func() {
		defer close(toFoodFighter)
		for {
			select {
			case <-done:
				return
			case toFoodFighter <- waiter(foods):
			}
		}
	}()
	return toFoodFighter
}

type FoodFighter struct {
	name    string
	current int
}

type FoodFighters []*FoodFighter

func (f *FoodFighter) eat(foods <-chan interface{}) *FoodFighter {
	food := <-foods
	f.current++
	fmt.Printf("%vは%vを%v個食べた\n", f.name, food, f.current)
	return f
}

func (f *FoodFighter) startEat(
	done <-chan interface{},
	foods <-chan interface{},
) <-chan *FoodFighter {
	results := make(chan *FoodFighter)
	go func() {
		defer close(results)
		for {
			select {
			case <-done:
				return
			case results <- f.eat(foods):
			}
		}
	}()
	return results
}

func start(done <-chan interface{}, f *FoodFighter) <-chan *FoodFighter {
	return f.startEat(done, waitperson(done, cook(done, hotDog)))
}

func competition(ctx context.Context, cancel context.CancelFunc, done <-chan interface{}) FoodFighters {
	defer cancel()
	var foodFighters FoodFighters
	var f1Result *FoodFighter
	var f2Result *FoodFighter
	var f3Result *FoodFighter
	f1 := &FoodFighter{name: "ボブ"}
	f2 := &FoodFighter{name: "ビル"}
	f3 := &FoodFighter{name: "マイケル"}

	for {
		select {
		case f1Result = <-start(done, f1):
		case f2Result = <-start(done, f2):
		case f3Result = <-start(done, f3):
		case <-ctx.Done():
			fmt.Println("大会終了です\n")
			foodFighters = append(foodFighters, f1Result)
			foodFighters = append(foodFighters, f2Result)
			foodFighters = append(foodFighters, f3Result)

			return foodFighters
		}
	}
}

func displayResult(results FoodFighters) {
	time.Sleep(1 * time.Second)
	fmt.Println("大会結果発表\n")

	sortedResults := From(results).Sort(func(f1, f2 interface{}) bool {
		return f1.(*FoodFighter).current > f2.(*FoodFighter).current
	}).Results()

	for i, fighter := range sortedResults {
		fmt.Printf("%v位: %v %v個\n", i+1, fighter.(*FoodFighter).name, fighter.(*FoodFighter).current)
	}
}

func foodFight() {
	done := make(chan interface{})
	defer close(done)

	limitTime := 2 * time.Second
	ctx, cancel := context.WithTimeout(context.Background(), limitTime)
	results := competition(ctx, cancel, done)

	displayResult(results)
}

func main() {
	foodFight()
}

実行結果

:
:
マイケルはホットドッグを417個食べた
ウェイターはホットドッグをフードファイターへ持っていきます。
ウェイターはホットドッグをフードファイターへ持っていきます。
コックはホットドッグを作ります
コックはホットドッグを作ります
ボブはホットドッグを447個食べた
コックはホットドッグを作ります
ビルはホットドッグを442個食べた
ウェイターはホットドッグをフードファイターへ持っていきます。
大会結果発表

1位: ボブ 447個
2位: ビル 442個
3位: マイケル 418個

goではselectのcase文全体に対して 擬似乱数による一様選択1 をしているらしい。
それぞれのcaseは等しく選択されていく。なので、結果は毎回、拮抗した感じになる。

  1. Go言語による並行処理 p81

2
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?