Goゴルーチン
Goのゴルーチンはグリーンスレッドで、goキーワードで起動します。
package main
import (
"fmt"
"time"
)
func printMessage(msg string) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(msg)
}
}
func main() {
go printMessage("world")
printMessage("hello")
}
チャネル
// 同期チャネルの基本操作
ch := make(chan int)
ch <- 10 // 送信
val := <-ch // 受信
// ゴルーチンとチャネルの連携
func calculateSum(numbers []int, result chan int) {
total := 0
for _, v := range numbers {
total += v
}
result <- total
}
data := []int{3, -2, 5, 7, -4, 8}
resultChan := make(chan int)
go calculateSum(data[:3], resultChan)
go calculateSum(data[3:], resultChan)
a, b := <-resultChan, <-resultChan
fmt.Println(a, b, a+b) // -4 15 11
// バッファ付きチャネル
buffered := make(chan int, 3)
buffered <- 100
buffered <- 200
fmt.Println(<-buffered)
fmt.Println(<-buffered)
buffered <- 300
チャネルのイテレーションとクローズ
func generateSequence(n int, out chan int) {
a, b := 0, 1
for i := 0; i < n; i++ {
out <- a
a, b = b, a+b
}
close(out)
}
seqChan := make(chan int, 8)
go generateSequence(cap(seqChan), seqChan)
for num := range seqChan {
fmt.Println(num)
}
チャネル選択
func sequenceGenerator(output, exit chan int) {
a, b := 0, 1
for {
select {
case output <- a:
a, b = b, a+b
case <-exit:
fmt.Println("シーケンス終了")
return
}
}
}
output := make(chan int)
exitSignal := make(chan int)
go func() {
for i := 0; i < 8; i++ {
fmt.Println(<-output)
}
exitSignal <- 0
}()
sequenceGenerator(output, exitSignal)
// タイムアウト処理
tickTimer := time.Tick(150 * time.Millisecond)
shutdown := time.After(1 * time.Second)
for {
select {
case <-tickTimer:
fmt.Println("イベント発生")
case <-shutdown:
fmt.Println("タイムアウト")
return
default:
fmt.Println("...")
time.Sleep(75 * time.Millisecond)
}
}
排他制御
type ThreadSafeCounter struct {
values map[string]int
lock sync.Mutex
}
func (c *ThreadSafeCounter) Increment(key string) {
c.lock.Lock()
c.values[key]++
c.lock.Unlock()
}
func (c *ThreadSafeCounter) Get(key string) int {
c.lock.Lock()
defer c.lock.Unlock()
return c.values[key]
}
counter := &ThreadSafeCounter{values: make(map[string]int)}
for i := 0; i < 500; i++ {
go counter.Increment("sample")
}
time.Sleep(500 * time.Millisecond)
fmt.Println(counter.Get("sample")) // 500
ゴルーチン同期
func executeTask(id int, group *sync.WaitGroup) {
fmt.Printf("タスク%d開始\n", id)
time.Sleep(1 * time.Second)
fmt.Printf("タスク%d完了\n", id)
group.Done()
}
var taskGroup sync.WaitGroup
for i := 1; i <= 3; i++ {
taskGroup.Add(1)
go executeTask(i, &taskGroup)
}
taskGroup.Wait()
fmt.Println("すべてのタスクが終了しました")