В КУРСЕ?

Разбираемся в теме

Конкурентность в Go: кто отвечает за общее состояние

Запуск нескольких горутин делает выполнение конкурентным, но не гарантирует правильную работу с общими данными. Если две задачи изменяют один счётчик, ошибка может возникнуть даже в очень коротком фрагменте программы. Начинать разбор полезно с вопроса о владельце состояния: кто вправе читать значение, кто его меняет и каким механизмом согласованы эти действия.

Разложите изменение на отдельные действия

Вообразим счётчик со значением десять. Первая задача читает десять, вторая тоже читает десять. Каждая вычисляет одиннадцать и записывает свой результат. Вместо двух увеличений получилось одно. Такая схема помогает понять потерянное обновление, хотя реальное поведение программы с гонкой нельзя свести только к этому порядку шагов. Выражение увеличения счётчика не становится безопасным из-за краткости записи. В Go конфликтующие обращения к общей памяти, не упорядоченные необходимой синхронизацией, могут образовать гонку данных, если хотя бы одно обращение является записью.

Защищайте целую операцию

Мьютекс может согласовать доступ к общему состоянию, если все участники соблюдают один протокол блокировки. Для операции «прочитать, проверить, изменить» защита должна охватывать всю связанную последовательность. Если отдельно защитить чтение и запись, между ними другая горутина может изменить значение. Представьте выдачу последнего свободного места: две задачи способны обе увидеть доступность, даже когда отдельные обращения не создают гонки данных. Значит, отсутствие гонки ещё не гарантирует правильность бизнес-правила. Сначала формулируют инвариант, например «число выданных мест не превышает вместимость», затем выбирают границы операции.

Отделите ожидание от владения

WaitGroup помогает дождаться завершения группы задач. Само ожидание не превращает конкурентные изменения общей переменной внутри этих задач в безопасные. Другая организация работы — передавать события через канал одной горутине, которая единолично обновляет счётчик. Тогда важно не оставлять обходные пути, позволяющие другим горутинам менять то же состояние напрямую. Канал также не решает автоматически вопросы остановки и ошибок. На схеме системы обозначьте владельца данных, отправителей сообщений и того, кто отвечает за завершение обмена. Выбор механизма должен делать правила доступа понятнее.

Проверяйте и обращения, и смысл результата

Детектор гонок запускают, например, командой go test -race. Его отчёт помогает найти конфликтующие обращения и места создания участвующих горутин. Но инструмент наблюдает выполненные пути: если опасный сценарий не возник во время запуска, отсутствие сообщения не доказывает безопасность всей программы. Дополнительно нужны проверки ожидаемого результата и ограничений предметной области. Для учебного счётчика это точное число обработанных событий, для распределения мест — отсутствие превышения вместимости. Случайная задержка или увеличение времени ожидания не заменяет синхронизацию: на другой нагрузке порядок выполнения снова изменится.

Попробуйте на практике

Разберите два варианта общего счётчика на бумаге, не запуская небезопасную программу.

  1. Запишите начальное значение десять и разложите два увеличения на чтение, вычисление и запись.
  2. Составьте порядок действий, в котором обе задачи читают исходное значение до первой записи, и вычислите итог.
  3. Нарисуйте вариант с одной общей блокировкой вокруг полного увеличения, затем вариант с единственным владельцем и двумя сообщениями.
  4. Для обоих решений укажите, кто может читать итог и как подтверждается завершение обработки всех событий.

Как проверить результат. В исходной схеме понятно, где теряется обновление. В исправленных схемах каждый доступ подчинён одному правилу, а ожидание завершения описано отдельно от защиты состояния.

Частые вопросы

Достаточно ли защищать только записи?

Нет, если чтения происходят конкурентно с изменениями. Все обращения к защищаемым данным должны соответствовать выбранному протоколу синхронизации.

Всегда ли канал лучше мьютекса?

Нет. Канал удобен для передачи сообщений и явного владельца состояния, мьютекс — для согласованного доступа к общим данным. Важнее простота проверяемых правил.

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

Зарегистрируйтесь, чтобы уточнить возможность доступа к этому материалу

Зарегистрироваться
← К списку материалов