Ускорение выполнения через параллельные запросы

Приведённая Do уже запускает fetchByName параллельно и защищает map. Для пяти пользователей время обычно близко к 10 мс плюс накладные расходы, но независимость от любого размера входа невозможна.

Короткий ответ

Что ответить на собеседовании

Приведённая Do уже запускает fetchByName параллельно и защищает map. Для пяти пользователей время обычно близко к 10 мс плюс накладные расходы, но независимость от любого размера входа невозможна.

Подробный разбор

Ответ с пояснениями

Условие

Необходимо доработать функцию Do так, чтобы её выполнение занимало около 10 мс независимо от количества переданных пользователей. Каждый вызов fetchByName имитирует задержку в 10 мс. Функции main и fetchByName менять нельзя – вся оптимизация должна быть реализована внутри Do.

package main

import (
    "context"
    "fmt"
    "math/rand"
    "sync"
    "time"
)

type User struct {
    Name string
}

func main() {
    fmt.Println(Do(context.Background(), []User{{"aaa"}, {"bbb"}, {"ccc"}, {"ddd"}, {"eeee"}}))
}

// fetchByName изменять нельзя
func fetchByName(ctx context.Context, userName string) (int, error) {
    time.Sleep(10 * time.Millisecond) // имитация сетевого похода
    return rand.Int() % 100000, nil
}

// все изменения должны происходить в этой функции
func Do(ctx context.Context, users []User) (map[string]int, error) {
    result := make(map[string]int)
    var mu sync.Mutex
    var wg sync.WaitGroup
    errCh := make(chan error, 1)

    for _, usr := range users {
        wg.Add(1)
        go func(u User) {
            defer wg.Done()
            id, err := fetchByName(ctx, u.Name)
            if err != nil {
                select {
                case errCh <- err:
                default:
                }
                return
            }
            mu.Lock()
            result[u.Name] = id
            mu.Unlock()
        }(usr)
    }

    wg.Wait()
    close(errCh)

    if err, ok := <-errCh; ok {
        return result, err
    }
    return result, nil
}

Ответ

Приведённая Do уже запускает fetchByName параллельно и защищает map. Для пяти пользователей время обычно близко к 10 мс плюс накладные расходы, но независимость от любого размера входа невозможна.

WaitGroup дожидается всех вызовов, mutex защищает записи, errCh сохраняет первую попавшую ошибку. При одинаковых именах итоговый ID недетерминирован: решите, объединять ли запросы. fetchByName игнорирует отмену во время Sleep, поэтому один контекст не остановит её раньше. Для больших наборов нужен лимит конкурентности, что увеличит общее время волнами; обещать постоянные 10 мс при неограниченном количестве пользователей нельзя.

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

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

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

Подробнее