Проверяет понимание ключевых аспектов конкурентности в Go и умение выявлять типичные ошибки при анализе кода.
Go предоставляет мощные инструменты для параллельного выполнения: горутины, каналы и примитивы синхронизации из пакета sync. Однако эти инструменты легко использовать неправильно, что приводит к трудноуловимым ошибкам. При анализе кода важно систематически проверять несколько аспектов.
Гонка данных возникает, когда две или более горутины одновременно обращаются к одной переменной, и хотя бы одна из них выполняет запись. Это приводит к непредсказуемому поведению. Для обнаружения используйте флаг -race при запуске тестов или программы. Пример опасного кода:
var counter int
for i := 0; i < 1000; i++ {
go func() {
counter++ // гонка!
}()
}Решение — использовать атомарные операции или мьютексы:
var mu sync.Mutex
var counter int
for i := 0; i < 1000; i++ {
go func() {
mu.Lock()
counter++
mu.Unlock()
}()
}Deadlock возникает, когда горутины ждут друг друга бесконечно. Например, если одна горутина блокирует мьютекс A и ждет B, а другая блокирует B и ждет A. Также часто встречается блокировка при чтении из пустого канала без отправителя. Проверяйте, что все каналы имеют отправителей и получателей, и что мьютексы всегда разблокируются (лучше через defer).
Горутина может остаться в памяти, если она блокируется навсегда, например, ожидая данные из канала, который никогда не получит значение. Используйте контексты (context.Context) для отмены операций и таймаутов. Также следите за тем, чтобы горутины завершались после выполнения своей работы.
Каналы — основной способ коммуникации. Важно помнить: закрытие канала должно происходить только отправителем, иначе возможна паника. Используйте range для чтения из канала, пока он открыт. Для сигнализации о завершении работы применяйте каналы типа struct{}.
Для ожидания завершения группы горутин используйте sync.WaitGroup. Не забывайте вызывать Add перед запуском каждой горутины и Done внутри нее. Пример:
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
// работа
}()
}
wg.Wait()При анализе Go-кода на конкурентность сосредоточьтесь на поиске гонок данных, блокировок и утечек горутин. Используйте встроенные инструменты, такие как детектор гонок, и следуйте идиоматическим паттернам: мьютексы для защиты общих данных, каналы для коммуникации, контексты для отмены. Это поможет создавать надежные и масштабируемые приложения.