Concurrency in Go Chapter1 (7)

“Concurrency in Go: Tools and Techniques for Developers”の1章 “An Introduction to Concurrency”の読書メモ。Starvationについて書く。

Starvationとは、あるプロセスがリソース(CPU、メモリ、ファイルハンドラ、DBのコネクションなど)を大量に消費してしまい、別のプロセスが実行するためリソースを確保できない状態を指す。

package mainimport (
"fmt"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
var sharedLock sync.Mutex
const runtime = 1 * time.Second
greedyWorker := func() {
defer wg.Done()
var count int
for begin := time.Now(); time.Since(begin) <= runtime; {
sharedLock.Lock()
time.Sleep(3 * time.Nanosecond)
sharedLock.Unlock()
count++
}
fmt.Printf("Greedy worker was able to execute %v work loops\n", count)
}
politeWorker := func() {
defer wg.Done()
var count int
for begin := time.Now(); time.Since(begin) < runtime; {
sharedLock.Lock()
time.Sleep(1 * time.Nanosecond)
sharedLock.Unlock()
sharedLock.Lock()
time.Sleep(1 * time.Nanosecond)
sharedLock.Unlock()
sharedLock.Lock()
time.Sleep(1 * time.Nanosecond)
sharedLock.Unlock()
count++
}
fmt.Printf("Polite worker was able to execute %v work loops\n", count)
}
wg.Add(2)
go greedyWorker()
go politeWorker()
wg.Wait()
}

Greedy workerは共有ロックの範囲が広く、Polite workerは共有ロックの範囲が狭くしているので、Greedy workerはPolite workerの約2倍実行されている。(Greedy workerはPolite workerの重要度が同じであれば、問題となる)

Greedy worker was able to execute 688386 work loops
Polite worker was able to execute 339861 work loops

Starvationを見つけるためにはログをとり、それぞれのプロセスが期待した比率で実行されていることを確認する必要がある。

リソースのロック、アンロックにコストがかかるため、ロックの範囲を広めた方が都合のよい場合はあるが、別のプロセスがリソースを確保できなくなるので、よいバランスを見つける必要がある。

Software engineer