Используйте атомарную проверку-и-добавление через sync.Map.LoadOrStore либо одну mutex-секцию для обычной map. Отдельные неблокированные чтения оставляют гонку.
Конкурентный вывод уникальных элементов среза
Используйте атомарную проверку-и-добавление через sync.Map.LoadOrStore либо одну mutex-секцию для обычной map. Отдельные неблокированные чтения оставляют гонку.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Дан срез целых чисел: values := []int{3, 3, 2, 1, 2, 1, 1, 2, 4}. Необходимо напечатать каждый различный элемент ровно один раз, используя несколько горутин. Порядок вывода не важен, главное – отсутствие повторов. В исходном примере происходит гонка данных при записи в обычную map, что приводит к некорректному результату. Нужно исправить код, обеспечив безопасный конкурентный доступ к общей структуре (например, через mutex или sync.Map).
func main() {
values := []int{3, 3, 2, 1, 2, 1, 1, 2, 4}
var idx map[int]struct{}
for _, v := range values {
go func() {
if _, ok := idx[v]; ok {
return
}
idx[v] = struct{}{}
log.Println(v)
}()
}
}
Ответ
Используйте атомарную проверку-и-добавление через sync.Map.LoadOrStore либо одну mutex-секцию для обычной map. Отдельные неблокированные чтения оставляют гонку.
Краткий вариант, нужны sync и log:
values := []int{3, 3, 2, 1, 2, 1, 1, 2, 4}
var seen sync.Map
var wg sync.WaitGroup
for _, value := range values {
wg.Add(1)
go func(n int) {
defer wg.Done()
if _, loaded := seen.LoadOrStore(n, struct{}{}); !loaded {
log.Println(n)
}
}(value)
}
wg.Wait()
Числа 1,2,3,4 выводятся каждое один раз, порядок произвольный. Передача аргумента исключает проблемы старой семантики цикла, WaitGroup не даёт main завершиться раньше печати.