Sobes.tech
Senior

func collectRTT(ctx context.Context, urls []string) (map[string]time.Duration, error) { pingMap := make(map[string]time.Duration, len(urls)) var mu sync.Mutex var wg sync.WaitGroup errCh := make(chan error, 1) for _, url := range urls { wg.Add(1) go func(u string) { defer wg.Done() dur, err := rtt(ctx, u) if err != nil { select { case errCh <- fmt.Errorf("failed to rtt %s, %w", u, err): default: } return } mu.Lock() pingMap[u] = dur mu.Unlock() }(url) } wg.Wait() close(errCh) if err := <-errCh; err != nil { return nil, err } return pingMap, nil }

sobes.tech AI

Answer from AI

The collectRTT function concurrently measures the response time (RTT) for a list of URLs using goroutines.

Key implementation points:

  • A separate goroutine is launched for each URL, which calls the rtt(ctx, u) function.
  • sync.WaitGroup is used to wait for all goroutines to finish.
  • A mutex mu is used for safe access to the shared map pingMap.
  • A buffered channel errCh with capacity 1 is used to pass the first error encountered from any goroutine.
  • If an error occurs, it is sent to errCh, but only one error is sent; others are ignored (via select with default).
  • After waiting for all goroutines, the error channel is closed, and if an error was received, the function returns it.

This approach allows efficient collection of RTTs for multiple URLs in parallel, handling errors gracefully and avoiding data races.

Example of using mutex and WaitGroup:

var mu sync.Mutex
var wg sync.WaitGroup
pingMap := make(map[string]time.Duration)

wg.Add(1)
go func() {
    defer wg.Done()
    dur := time.Millisecond * 100 // example
    mu.Lock()
    pingMap["example.com"] = dur
    mu.Unlock()
}()

wg.Wait()