package main import ( "fmt" "math/rand" "time" ) func main() { defer fmt.Println("Finished") fmt.Println("Hello world") var results = requestAll([]string{"http://test.com", "http://test2.com"}) for _, result := range results { fmt.Printf("Result: %s\n", result) } } func mockHTTPRequest(url string) string { timeDelay := rand.Intn(3000) time.Sleep(time.Duration(timeDelay) * time.Millisecond) return fmt.Sprintf("OK: Request %s %d ms\n", url, timeDelay) } func requestAll(urls []string) []string { var length = len(urls) requests := make(chan string, length) defer close(requests) // Use goroutine to send multiple time-consuming jobs to the channel. for _, url := range urls { go func(url2 string) { requests <- mockHTTPRequest(url2) }(url) } var responses = make([]string, 0, length) for i := 0; i < length; i++ { var response = <-requests responses = append(responses, response) } return responses }
Extended example:
package main import ( "fmt" "io" "net/http" "os" "time" ) type Download interface { getFile() string getUrl() string getDuration() time.Duration setDuration(value time.Duration) getError() error setError(value error) } type DownloadInfo struct { file string url string err error duration time.Duration } func (r *DownloadInfo) getFile() string { return r.file } func (r *DownloadInfo) getUrl() string { return r.url } func (r *DownloadInfo) setDuration(value time.Duration) { r.duration = value } func (r *DownloadInfo) getDuration() time.Duration { return r.duration } func (r *DownloadInfo) setError(value error) { r.err = value } func (r *DownloadInfo) getError() error { return r.err } func createDownload(url string, file string) *DownloadInfo { return &DownloadInfo{ url: url, file: file, duration: 0, } } func main() { defer fmt.Println("Finished") fmt.Println("Hello world") var data = []Download{ createDownload("https://download.visualstudio.microsoft.com/download/pr/15ab772d-ce5c-46e5-a90e-57df11adabfb/4b1b1330b6279a50c398f94cf716c71e/dotnet-sdk-6.0.301-win-x64.exe", "dotnet-sdk-6.0.301-win-x64.exe"), createDownload("https://download.visualstudio.microsoft.com/download/pr/7989338b-8ae9-4a5d-8425-020148016812/c26361fde7f706279265a505b4d1d93a/dotnet-runtime-6.0.6-win-x64.exe", "dotnet-runtime-6.0.6-win-x64.exe"), createDownload("https://download.visualstudio.microsoft.com/download/pr/test", "fail.txt"), } var results = requestAll(data) for _, result := range results { var err = result.getError() if err != nil { fmt.Printf("Result: %s -X %s\n", result.getUrl(), err) } else { fmt.Printf("Result: %s -> %s : %s\n", result.getUrl(), result.getFile(), result.getDuration()) } } } func startDownload(d Download) Download { var start = time.Now() fmt.Printf("Start: %s\n", d.getUrl()) resp, err := http.Get(d.getUrl()) if err != nil { // setErr(err) return d } defer resp.Body.Close() var success = resp.StatusCode >= 200 && resp.StatusCode < 400 if !success { d.setError(fmt.Errorf("Failed with exit code %d", resp.StatusCode)) return d } out, err := os.Create(d.getFile()) if err != nil { return d } defer out.Close() _, err = io.Copy(out, resp.Body) if err != nil { return d } var elapsed = time.Since(start) d.setDuration(elapsed) fmt.Printf("End: %s : %s s\n", d.getUrl(), elapsed) return d } func requestAll(downloads []Download) []Download { var length = len(downloads) requests := make(chan Download, length) defer close(requests) // Use goroutine to send multiple time-consuming jobs to the channel. for _, d := range downloads { go func(d2 Download) { requests <- startDownload(d2) }(d) } var responses = make([]Download, 0, length) for i := 0; i < length; i++ { var response = <-requests responses = append(responses, response) } return responses }
627900cookie-checkGo Simple ‘Async’ function