Перед вами багованный загрузчик профилей пользователей. FetchUsersData
получает список userIDs, параллельно запрашивает профили через
fetchFromRemoteAPI (имитация медленного HTTP-вызова) и кэширует результаты,
чтобы не дёргать API дважды по одному id.
Код компилируется, но содержит ошибку конкурентности: воркеры-горутины
дописывают результаты в общий слайс results без синхронизации — это гонка
данных, которая под -race приводит к падению, а в проде — к потерянным или
повреждённым записям.
type UserProfile struct {
ID int
Name string
}
type UserFetcher struct {
// ...
}
func NewUserFetcher() *UserFetcher
// FetchUsersData возвращает по одному профилю на каждый запрошенный id
// (повторы в запросе допускаются и должны давать повторы в ответе).
func (uf *UserFetcher) FetchUsersData(userIDs []int) []UserProfile
Ваша задача — найти и исправить ВСЕ ошибки так, чтобы функция возвращала
корректный набор профилей (по одному на каждый запрошенный id, с учётом
повторов) и не содержала гонок данных. Кэш должен предотвращать повторные
обращения к API по одному id, но доступ к нему и к результатам обязан быть
потокобезопасным.
Скрытый тест запускается под детектором гонок (-race) и проверяет количество и
содержимое результатов. Если останется гонка данных или потеряются записи — тест
упадёт.
На что смотрит интервьюер:
- Гонка данных на общем слайсе результатов: несколько воркеров делают
append в один и тот же слайс без синхронизации. Нужно собирать результаты
потокобезопасно (мьютекс, канал результатов или предвыделенный слайс с записью
по индексу).
- Потокобезопасный кэш: конкурентный доступ к map должен быть под защитой;
без неё возможны как гонки, так и дублирующие обращения к API.
- Полнота результата: на каждый запрошенный id (включая повторы) в ответе
должна быть ровно одна запись с корректным
Name.
- Ограниченный параллелизм: фиксированный пул воркеров (например, 5),
читающих id из канала, без неограниченного числа горутин.
- Чистота под
-race: отсутствие любых data race.