Найти и исправить ошибку в генерации и фильтрации случайных чисел

Нужно создать 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 проще.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее