Нужно создать map, защищать проверку и вставку одним lock и закрыть uniqueIDs после всех отправителей. Иначе есть panic, гонка и зависание range.
Найти и исправить ошибку в генерации и фильтрации случайных чисел
Нужно создать map, защищать проверку и вставку одним lock и закрыть uniqueIDs после всех отправителей. Иначе есть panic, гонка и зависание range.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Требуется поправить программу, которая генерирует набор случайных целых чисел от 0 до 9, отбирает среди них дублирующиеся элементы, проверяет их на уникальность и передаёт только уникальные значения в канал.
// select only unique values
func main() {
var alreadyStored map[int]struct{}
mu := sync.Mutex{}
capacity := 1000
doubles := make([]int, 0, capacity)
for i := 0; i < capacity; i++ {
doubles = append(doubles, rand.Intn(10)) // create rand num 0..9
}
// 3, 4, 5, 0, 4, 9, 9, 8, 6, 6, 5, 5, 4, 4, 2, 1, 2, 3, 1 ...
uniqueIDs := make(chan int, capacity)
wg := sync.WaitGroup{}
for i := 0; i < capacity; i++ {
i := i
wg.Add(1)
go func() {
defer wg.Done()
if _, ok := alreadyStored[doubles[i]]; !ok {
mu.Lock()
alreadyStored[doubles[i]] = struct{}{}
mu.Unlock()
uniqueIDs <- doubles[i]
}
}()
}
wg.Wait()
for val := range uniqueIDs {
fmt.Println(val)
}
fmt.Println(uniqueIDs)
}
Ответ
Нужно создать map, защищать проверку и вставку одним lock и закрыть uniqueIDs после всех отправителей. Иначе есть panic, гонка и зависание range.
После генерации doubles основную часть можно заменить так:
alreadyStored := make(map[int]struct{})
uniqueIDs := make(chan int, len(doubles))
var mu sync.Mutex
var wg sync.WaitGroup
for _, value := range doubles {
wg.Add(1)
go func(value int) {
defer wg.Done()
mu.Lock()
_, exists := alreadyStored[value]
if !exists { alreadyStored[value] = struct{}{} }
mu.Unlock()
if !exists { uniqueIDs <- value }
}(value)
}
wg.Wait()
close(uniqueIDs)
for value := range uniqueIDs { fmt.Println(value) }
Буфер вмещает все возможные отправки, поэтому ожидание до чтения здесь безопасно. Результат — каждое встретившееся число один раз, не числа с частотой ровно один. Для диапазона 0–9 тысяча горутин избыточна: последовательная отметка в [10]bool проще.