Инструменты конкурентного программирования в GO для самых маленьких

Содержание:

  1. Горутины
  2. WaitGroup
  3. Каналы
  4. Select
  5. Mutex (для борьбы с Race Condition – Состояние гонки)

 

1. Горутины (#14)

Функция, которая не блокирует, работает асинхронно (не однопоточно)

Не ждём пока выполнится горутина, она идёт своим ответвление от потока.

Существует очередь выполнения горутин (ей занимается планировщик горутин).

Функция main – горутина.

Переключение горутин происходит при блокировки текущей горутины.

Блокировка в GO:

  • Функция time.Sleep(time.Nanosecond)
  • Чтение запись в канал и из канала
  • Использование спец. примитивов синхронизации из пакета Sync
  • Операции Input / Output – чтение из консоли, или работа по сети (когда посылается запрос)

Анонимные функции – можно вызывать в горутинах анонимные функции. Так часто делают.

***

2. WaitGroup (ждать группа, подождать группу) (#15)

Блокирует до тех пор, пока есть хотя бы одна задача ("группа ожидания") которую нужно подождать. 

(можно например как альтернативу использовать time.Sleep(…), но тогда нам придётся подгадывать время ожидания, получится либо меньше чем надо, либо излишни много, чем надо)

Синтаксис:

  • 0) wg := &sync.WaitGroup{}
  • 1) wg.Add(1) – добавляет задачу (группу ожидания). 1 горутина = одна задача
  • В функцию передать аргументом указатель на wg: func saveUserInfo(user User, wg *sync.WaitGroup) error { … }
  • 2) wg.Done() – означает, что одна задача выполненна (декриментит 1 добавленную wg.Add(1))

    wg.Done() – как правило находится в самом конце функции горутины, перед return

WaitGroup – по простому, некий счётчик, который блокирует, если есть хотя бы одна задача. И разблокирует, когда счётчик - станет = 0.

  • wg.Wait() – когда интерпритатор доходит до этой строки - он блокирует выполнение программы до тех пор пока счётчик не станет 0. За счёт чего планировщик переключается на горутины.
    По простому wg.Wait() – ждёт 0 в счётчике

Ещё раз, ВАЖНО: Код после wg.Done() выполнится только когда счётчик wg будет равен 0.

***

3. Каналы (#16)

Коммуникация между Горутинами. Для обмена информацией между горутинами.

Синтаксис:

  • var msg chan string // (ключевое слово chan)

Неинициализированный канал = nil

После инициализации Println выводит адрес в памяти - т.е. это указатель

  • msg = make(chan string) // инициализация канала
  • msg <- "Канал Ниндзя" // запись в канал строки

Запись в канал – блокирующая операция

  • value := <- msg // читает (считывает) из канала в переменную
  • fmt.Println (<-msg) // это тоже самое, что и выше, только без переменной

deadlock – мёртвая блокировка (все горутины в спящем, ждущем режиме)

Канал должен обязательно кем-то читаться (в горутине? main тоже горутина)

Буферизированный канал – когда канал буферизирован – есть буфер, т.е. происходит запись в канал без блокировки (не происходит дэдлока), пока значения помещаются в буфер и не превышают его размер (3 шт, например)

Небуферизированный канал блокируется на записи (для дальнешего чтения)

Синтаксис:

  • msg := make(chan string, 3) // 3 размер буффера

Про каналы:

 

 

Ещё ссылки по GO

https://sefus.ru/little-go-book/ – Маленькая книга о Go

 

Связаться с автором Поддержать автора (что?)

Комментарии

Если у вас есть вопрос, критика или другое мнение - напишите в комментариях.