Skip to content

第10回Go勉強会の課題@luccafort #58

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 32 additions & 13 deletions goroutine/sleep_sort/main.go
Original file line number Diff line number Diff line change
@@ -1,37 +1,56 @@
package main

import (
"errors"
"fmt"
"log"
"sync"
"time"

"golang.org/x/sync/errgroup"
)

// mutex
var mu sync.Mutex
var sortedNums []int
Copy link
Author

@luccafort luccafort Apr 29, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[コメント]

そういえば今回グローバル領域に変数を定義したわけだけど個人的にはあまりグローバル領域に変数を定義したくないわけで、じゃあどうすればいいのか?ってところまで突き詰められてなかった。


func main() {
var eg errgroup.Group
nums := []int{1, 3, 2, 5, 4}

// mutexを使わずにChannelを使う方が楽
// Channelは別の回でやるので、Goroutineだけで頑張る例
sortedNums := make([]int, 0, len(nums))

for _, num := range nums {
// goroutineでは無名関数も使える
// ここでnumを渡す事で、forが進んでも各Goroutineのスコープ内でnは変化しない。
go func(n int) {
// n秒スリープする
time.Sleep(time.Duration(n) * time.Second)
// mutexのLock
// 他のGoroutineからのアクセスがブロックされる
mu.Lock()
// deferで必ずUnlockする
defer mu.Unlock()
sortedNums = append(sortedNums, n)
}(num) // (num)が無名関数の引数
eg.Go(SleepLessThan100(num))
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[コメント]

この eg.Go でラップするのが少し気になった。
JSのように async / awaitな構文が欲しくなったけどそれだと多分隠蔽しすぎてるという思想なのかなと思った。
JSのように動的言語であればそっちのほうが嬉しいけど型のある世界でそれを隠蔽してしまうと副作用も隠蔽することになるので明示的に宣言させてそうだなって思いました。

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

あとJSと違って複数のGoroutineの終了を同期したい、みたいな要件も違ってるだろうなというのがある。

}

time.Sleep(6 * time.Second)
// 全てのGoroutineの実行完了を待ち、1つ目のエラーを起こす
if err := eg.Wait(); err != nil {
log.Fatal(err)
}
fmt.Println(sortedNums)
}

func init() {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

雰囲気で特殊な組み込み関数をオーバーライドしていてmain関数の実行前に初期化処理が行えるんだろうな、くらいに考えてた。
https://qiita.com/tenntenn/items/7c70e3451ac783999b4f

sortedNums = []int{}
}

// SleepLessThan100 using SleepSort and return error when variable more than 100.
func SleepLessThan100(n int) func() error {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[コメント]

戻り値の型指定で func() error を返すというのがどうにも違和感がある。
ただこれは慣れの問題かなと思ってる。

return func() error {
if n >= 100 {
return errors.New("n must be less than 100")
}
// n秒スリープする
time.Sleep(time.Duration(n) * time.Second)
Copy link
Author

@luccafort luccafort Apr 29, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[コメント]

Sleep Sortというソートの概念知らなかった。
知らないアルゴリズムだったのでめちゃくちゃ難しいことしてるのか!?と思ったら逆だったのウケる

// mutexのLock
// 他のGoroutineからのアクセスがブロックされる
mu.Lock()
// deferで必ずUnlockする
defer mu.Unlock()
sortedNums = append(sortedNums, n)
return nil
}
}