Sobes.tech
Junior — Senior

Acceleration of execution through parallel requests

livecode

Task condition

It is necessary to refine the Do function so that its execution takes about 10 ms regardless of the number of users passed. Each call to fetchByName simulates a delay of 10 ms. The functions main and fetchByName cannot be changed — all optimization must be implemented inside 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 cannot be changed
func fetchByName(ctx context.Context, userName string) (int, error) {
    time.Sleep(10 * time.Millisecond) // simulate network delay
    return rand.Int() % 100000, nil
}

// All changes should be made in this function
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
}