2019-10-08 17:09:19 +03:00

87 lines
2.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// В предыдущем примере мы увидели, как управлять простым
// состоянием счетчика с помощью [атомарных операций](atomic-counters).
// Для более сложного состояния мы можем использовать <em>мьютекс(http://en.wikipedia.org/wiki/Mutual_exclusion)</em>
// для безопасного доступа к данным в нескольких горутинах.
package main
import (
"fmt"
"math/rand"
"sync"
"sync/atomic"
"time"
)
func main() {
// Для нашего примера `state` будет картой.
var state = make(map[int]int)
// Этот `mutex` будет синхронизировать доступ к `state`.
var mutex = &sync.Mutex{}
// Мы будем отслеживать, сколько операций чтения и
// записи мы выполняем.
var readOps uint64
var writeOps uint64
// Здесь мы запускаем 100 горутин для выполнения
// повторных операций чтения по состоянию, один раз
// в миллисекунду в каждой горутине.
for r := 0; r < 100; r++ {
go func() {
total := 0
for {
// Для каждого чтения мы выбираем ключ для
// доступа, блокируем `mutex` с помощью `Lock()` ,
// чтобы обеспечить исключительный доступ к
// `состоянию`, читаем значение в выбранном ключе,
// разблокируем мьютекс `Unlock()` и увеличиваем
// количество `readOps`.
key := rand.Intn(5)
mutex.Lock()
total += state[key]
mutex.Unlock()
atomic.AddUint64(&readOps, 1)
// Немного ждем между чтениями.
time.Sleep(time.Millisecond)
}
}()
}
// Запустим так же 10 горутин для симуляции записи,
// так же как мы делали для чтения.
for w := 0; w < 10; w++ {
go func() {
for {
key := rand.Intn(5)
val := rand.Intn(100)
mutex.Lock()
state[key] = val
mutex.Unlock()
atomic.AddUint64(&writeOps, 1)
time.Sleep(time.Millisecond)
}
}()
}
// Пусть 10 горутин работают над `состоянием` и
// `мьютексом` на секунду.
time.Sleep(time.Second)
// Смотрим финальное количество операций
readOpsFinal := atomic.LoadUint64(&readOps)
fmt.Println("readOps:", readOpsFinal)
writeOpsFinal := atomic.LoadUint64(&writeOps)
fmt.Println("writeOps:", writeOpsFinal)
// С окончательной блокировкой `состояния` смотрим,
// как все закончилось.
mutex.Lock()
fmt.Println("state:", state)
mutex.Unlock()
}