Middle+
Task: "Parallel URL processing with timeout limit" Write a function fetchAll(urls []string, maxParallel int, timeout time.Duration) map[string]string, which: 1. Performs an HTTP GET request for each URL (using http.Get). 2. Returns a map[string]string where the key is the URL, and the value is the response body (as a string) or an empty string on error/timeout. 3. Executes no more than maxParallel requests simultaneously. 4. The total runtime of the function should not exceed timeout. If the timeout expires, all unfinished requests are interrupted, and the function returns what it has. 5. Use context for cancellation.
sobes.tech AI
Answer from AI
go package main
import ( "context" "io/ioutil" "net/http" "sync" "time" )
func fetchAll(urls []string, maxParallel int, timeout time.Duration) map[string]string { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel()
results := make(map[string]string)
var mu sync.Mutex
sem := make(chan struct{}, maxParallel) // semaphore to limit parallelism
var wg sync.WaitGroup
for _, url := range urls {
select {
case <-ctx.Done():
break
default:
wg.Add(1)
sem <- struct{}{} // acquire slot
go func(u string) {
defer wg.Done()
defer func() { <-sem }() // release slot
req, err := http.NewRequestWithContext(ctx, "GET", u, nil)
if err != nil {
mu.Lock()
results[u] = ""
mu.Unlock()
return
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
mu.Lock()
results[u] = ""
mu.Unlock()
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
mu.Lock()
results[u] = ""
mu.Unlock()
return
}
mu.Lock()
results[u] = string(body)
mu.Unlock()
}(url)
}
}
wg.Wait()
return results
}