Kristina K creaturek

Cинхронность отправки и получения данных по небуферизированным каналам в Go

Листала книгу, в которой пригляделся пример с небуферизированными каналами:

alt text alt text

Эмулируется игра в теннис с двумя игроками. Игрок представлен горутиной, которая читывают и записывают в канал значение (перекидывание мячика). Вывод был следующий:

alt text

Резонно возникает вопрос: можно ли быть уверенным в том, что значение, которая передала первая горутина (строка 32), прочитает вторая горутина (строка 45), а не та же, что и отправила? Иными сломами, может ли возникнуть ситуация, при которой вывод программы будет следующий:

Player Nahal Hit 1
Player Djokovic 2 
Player Nahal Hit 3
Player Nahal Hit 4 // здесь горутина, готорая отправила "мячик", его же и получила
Player Djokovic 5

Вооруживщись отсылкой к авторитетам с предположением, что автор книги более компетентен, я начала размышлять, по какой причине так уверенно было реализовано чтение и запись в одной функции без боязни незапланированного чтения значения одной и той же горутиной. Первой мыслью было детерминированная последовательная передача ресурсов из канала планировщиком горутинам в последовательности, как они “были зарегестрированы” на получение данных. То есть если вторая горутина первая встала в очерeдь на чтение, то при записи однозначно ей будет переданы данные на чтение. Эта версия, однако, весьма сомнительная, потому что в буферизированных каналах чтение и запись из канала планировщик осуществляет в случайном порядке (для примера достаточен любой код с несколькими горутинами и capacity канала больше, чем 1, хоть этот).

Ответ гораздо красивее: запись в небуферизированый канал выполняется синхронно с чтением. Даже так: CSP Go работает таким образом, что чтение в канал (но только небуферизированный) выполняется раньше, чем заканчивается запись. Для нас это значит, что в тот момент, когда первая горутина отправила в значение (строка 32), она заблокировалась. Так что мячик в любом случае принимает вторая горутина (второй игрок) и все работает как и предполагалось.

Отличная иллюстрация поведения канала (а именно: его блокировки до момента чтения) из [3]:

alt text

Подробнее:

  1. Самое простое - внимательно читать книги, а не рывками хватать информацию, в Go action это также упомянуто.
  2. Официальная документация
  3. The Nature Of Channels In Go
  4. Are waiting sends to an unbuffer channel ordered - Google groups