Введение в синхронизацию в Go
Синхронизация не дает двум горутинам одновременно портить одно общее значение. Пока одна ветка меняет счетчик или карту, другая может прочитать половину записи или затереть чужое приращение, если доступ не согласован.
Гонка за память проявляется не каждый запуск: итог может совпасть с ожиданием случайно, а на другой машине или при большем числе веток цифра уедет. Такой баг трудно ловить, поэтому общие переменные защищают заранее, а не после жалоб на неверный результат.
В стандартной библиотеке для этого есть
замок взаимного исключения, замок с
отдельными правилами для чтения и записи,
команда однократного запуска и атомарные
операции над числом. Каналы тоже помогают
передавать данные без гонки, но когда
нужен именно общий счетчик или одноразовая
инициализация, удобнее прямые средства
из пакета sync и sync/atomic.
В этом разделе сначала разберем замок для счетчика, затем несколько читателей и одного писателя, однократный вызов функции и приращение без отдельного замка. В конце закрепим приемы на задачах. Ожидание группы горутин уже знакомо; здесь оно лишь дожидается веток в примерах, а не становится новой темой.