управление состоянием горутин

This commit is contained in:
badkaktus 2019-10-08 21:40:13 +03:00
parent be57797702
commit 80e08633e1
3 changed files with 51 additions and 42 deletions

View File

@ -36,7 +36,7 @@ WaitGroups
Ограничение скорости (Rate Limiting) Ограничение скорости (Rate Limiting)
Атомарные счетчики (Atomic Counters) Атомарные счетчики (Atomic Counters)
Мьютексы (Mutexes) Мьютексы (Mutexes)
Stateful Goroutines Управление состоянием горутин (Stateful Goroutines)
Sorting Sorting
Sorting by Functions Sorting by Functions
Panic Panic

View File

@ -1,11 +1,11 @@
// In the previous example we used explicit locking with // В предыдущем примере мы использовали явную блокировку
// [mutexes](mutexes) to synchronize access to shared state // с [мьютексами](mutexes) для синхронизации доступа к
// across multiple goroutines. Another option is to use the // общему состоянию между несколькими горутинами. Другой
// built-in synchronization features of goroutines and // вариант - использовать встроенные функции синхронизации
// channels to achieve the same result. This channel-based // для горутин и каналов для достижения того же результата.
// approach aligns with Go's ideas of sharing memory by // Этот подход, основанный на каналах, согласуется с идеями
// communicating and having each piece of data owned // Go о совместном использовании памяти путем обмена
// by exactly 1 goroutine. // данными и владения каждой частью данных ровно 1 горутиной.
package main package main
@ -16,6 +16,14 @@ import (
"time" "time"
) )
// В этом примере наше состояние будет принадлежать
// единственной горутине. Это гарантирует, что данные
// никогда не будут повреждены при одновременном доступе.
// Чтобы прочитать или записать это состояние, другие
// горутины будут отправлять сообщения горутин-владельцу
// и получать соответствующие ответы. Эти `структуры`
// `readOp` и `writeOp` инкапсулируют эти запросы и
// способ, которым владеет горутина-ответчик.
// In this example our state will be owned by a single // In this example our state will be owned by a single
// goroutine. This will guarantee that the data is never // goroutine. This will guarantee that the data is never
// corrupted with concurrent access. In order to read or // corrupted with concurrent access. In order to read or
@ -36,25 +44,26 @@ type writeOp struct {
func main() { func main() {
// As before we'll count how many operations we perform. // Как и прежде, мы посчитаем, сколько операций мы
// выполняем.
var readOps uint64 var readOps uint64
var writeOps uint64 var writeOps uint64
// The `reads` and `writes` channels will be used by // Каналы `чтения` и `записи` будут использоваться
// other goroutines to issue read and write requests, // другими горутинами для выдачи запросов на чтение
// respectively. // и запись соответственно.
reads := make(chan readOp) reads := make(chan readOp)
writes := make(chan writeOp) writes := make(chan writeOp)
// Here is the goroutine that owns the `state`, which // Эта горутина, которой принадлежит состояние, она же
// is a map as in the previous example but now private // является картой, как в предыдущем примере, но теперь
// to the stateful goroutine. This goroutine repeatedly // является частной для горутины с сохранением состояния.
// selects on the `reads` and `writes` channels, // Она постоянно выбирает каналы `чтения` и `записи`,
// responding to requests as they arrive. A response // отвечая на запросы по мере их поступления. Ответ
// is executed by first performing the requested // выполняется, сначала выполняя запрошенную операцию,
// operation and then sending a value on the response // а затем отправляя значение по каналу `resp`,
// channel `resp` to indicate success (and the desired // соответственно, чтобы указать успешность (и
// value in the case of `reads`). // ребуемое значение в случае `reads`).
go func() { go func() {
var state = make(map[int]int) var state = make(map[int]int)
for { for {
@ -68,11 +77,11 @@ func main() {
} }
}() }()
// This starts 100 goroutines to issue reads to the // Запускаем 100 горутин для выдачи операций чтения
// state-owning goroutine via the `reads` channel. // в горутину владеющую состоянием, через канал `reads`.
// Each read requires constructing a `readOp`, sending // Каждое чтение требует создания `readOp`, отправки
// it over the `reads` channel, and the receiving the // его по каналу `reads` и получения результата по
// result over the provided `resp` channel. // `resp` каналу.
for r := 0; r < 100; r++ { for r := 0; r < 100; r++ {
go func() { go func() {
for { for {
@ -87,8 +96,7 @@ func main() {
}() }()
} }
// We start 10 writes as well, using a similar // Так же делаем 10 записей.
// approach.
for w := 0; w < 10; w++ { for w := 0; w < 10; w++ {
go func() { go func() {
for { for {
@ -104,10 +112,10 @@ func main() {
}() }()
} }
// Let the goroutines work for a second. // Дадим горутинам отработать 1 секунду
time.Sleep(time.Second) time.Sleep(time.Second)
// Finally, capture and report the op counts. // Наконец, выводим данные счетчиков
readOpsFinal := atomic.LoadUint64(&readOps) readOpsFinal := atomic.LoadUint64(&readOps)
fmt.Println("readOps:", readOpsFinal) fmt.Println("readOps:", readOpsFinal)
writeOpsFinal := atomic.LoadUint64(&writeOps) writeOpsFinal := atomic.LoadUint64(&writeOps)

View File

@ -1,15 +1,16 @@
# Running our program shows that the goroutine-based # Запуск нашей программы показывает, что управление
# state management example completes about 80,000 # состоянием на основе горутин завершает около
# total operations. # 80 000 операций.
$ go run stateful-goroutines.go $ go run stateful-goroutines.go
readOps: 71708 readOps: 71708
writeOps: 7177 writeOps: 7177
# For this particular case the goroutine-based approach # Для этого конкретного случая подход, основанный на
# was a bit more involved than the mutex-based one. It # горутине, был немного более сложным, чем подход,
# might be useful in certain cases though, for example # основанный на мьютексе. Это может быть полезно в
# where you have other channels involved or when managing # некоторых случаях, например, когда задействованы
# multiple such mutexes would be error-prone. You should # другие каналы или при управлении несколькими такими
# use whichever approach feels most natural, especially # мьютексами могут возникать ошибки. Вы должны
# with respect to understanding the correctness of your # использовать тот подход, который кажется вам наиболее
# program. # естественным, особенно в отношении понимания
# правильности вашей программы.