Go Simple ‘Async’ function

Date: 2022-05-31
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
}
62790cookie-checkGo Simple ‘Async’ function