Будет ли чтение переменной тремя горутинами происходить параллельно или последовательно в Go
Что проверяют
Различаете ли вы конкурентность и параллелизм и знаете ли, когда одновременный доступ к переменной становится гонкой. Следом обычно спрашивают, что изменится, если четвёртая горутина начнёт писать, и чем здесь sync.RWMutex лучше sync.Mutex.
Как отвечать
Ответ «зависит» нужно раскрыть:
- параллельно ли: горутины исполняются на потоках ОС, а
GOMAXPROCSограничивает, сколько потоков выполняют Go-код одновременно. По умолчанию это число логических ядер, а с Go 1.25 на Linux учитывается и лимит CPU контейнера. При нескольких ядрах три чтения могут идти физически одновременно, приGOMAXPROCS=1они чередуются на одном потоке. Порядок в любом случае не гарантирован; - безопасно ли: гонка данных по модели памяти Go это одновременный доступ из разных горутин без синхронизации, где хотя бы один доступ пишет. Одни чтения гонкой не являются, блокировка им не нужна;
- видимость: значение, записанное до оператора
go, горутина гарантированно увидит, запуск горутины устанавливает отношение happens-before; - если есть писатель: нужна синхронизация.
sync.RWMutexпускает читателей параллельно черезRLock, а писателя эксклюзивно. Для редко меняемого значения подходятatomic.Pointer[T]илиatomic.Value, для однократной инициализацииsync.Once. Каналы уместны, когда данные передаются владельцу, а не когда их просто читают.
Своё утверждение подкрепите инструментом: go test -race или go run -race ловит гонки во время выполнения.
Где спотыкаются
Оборачивают каждое чтение в sync.Mutex. Три читателя тогда выстраиваются в очередь, то есть ответ «последовательно» кандидат создаёт сам.
Считают, что чтение int на процессоре атомарно, значит писатель рядом безопасен. Для модели памяти Go это всё равно гонка: компилятор вправе переупорядочить или закешировать доступ, результат не определён.
Ставят time.Sleep вместо sync.WaitGroup и путают конкурентность с параллелизмом: горутины конкурентны всегда, а параллельны только при свободных ядрах.