Skip to content

Instantly share code, notes, and snippets.

@kazimanzurrashid
Last active August 9, 2022 17:14
Show Gist options
  • Save kazimanzurrashid/1de68297833d4d9f3893c418c1f42bf4 to your computer and use it in GitHub Desktop.
Save kazimanzurrashid/1de68297833d4d9f3893c418c1f42bf4 to your computer and use it in GitHub Desktop.
Use workerpool to download multiple files concurrently from a json file in golang
{
"urls": [
"https://i.pinimg.com/236x/0d/a8/87/0da8872e1ca3e247aef7f75f64a75a5f--learn-coding-logos.jpg",
"https://www.evanmiller.org/images/four-days-of-go/gopher3.png",
"https://talks.golang.org/2013/highperf/aegopher.jpg",
"http://gophercloud.io/public/logo.png",
"https://forum.golangbridge.org/uploads/default/original/2X/0/03cbc1a9f9178055093eb0c25ba9df2c29611671.png",
"https://cdn.chrisshort.net/testing-certificate-chains-in-go/GOPHER_MIC_DROP.png"
]
}
package main
import (
"encoding/json"
"log"
"net/http"
"os"
"path"
"testdrive/workerpool"
)
const dataDir string = "./data"
type input struct {
URLs []string `json:"urls"`
}
func download(url string) bool {
res, err := http.Get(url)
if err != nil || res.StatusCode != http.StatusOK {
return false
}
defer func() {
_ = res.Body.Close()
}()
file, err := os.Create(path.Join(dataDir, path.Base(url)))
if err != nil {
panic(err)
}
defer func() {
_ = file.Close()
}()
if _, err = file.ReadFrom(res.Body); err != nil {
panic(err)
}
return true
}
func main() {
content, err := os.ReadFile(os.Args[1])
if err != nil {
panic(err)
}
var input input
if err = json.Unmarshal(content, &input); err != nil {
panic(err)
}
_ = os.Mkdir(dataDir, os.ModeDir)
wp := workerpool.New(len(input.URLs), 3)
defer wp.Dispose()
wp.Run()
for _, url := range input.URLs {
func(url string) {
wp.Enqueue(func() {
log.Printf("Downloading: %v", url)
downloaded := download(url)
if downloaded {
log.Printf("Downloaded: %v", url)
} else {
log.Printf("Failed to download: %v", url)
}
})
}(url)
}
wp.Wait()
}
package workerpool
type WorkerPool struct {
total int
concurrent int
tasks chan func()
done chan bool
}
func (wp *WorkerPool) Run() {
for i := 0; i < wp.concurrent; i++ {
go func() {
for task := range wp.tasks {
task()
wp.done <- true
}
}()
}
}
func (wp *WorkerPool) Enqueue(task func()) {
wp.tasks <- task
}
func (wp *WorkerPool) Wait() {
for i := 0; i < wp.total; i++ {
<-wp.done
}
}
func (wp *WorkerPool) Dispose() {
close(wp.tasks)
close(wp.done)
}
func New(total, concurrent int) *WorkerPool {
return &WorkerPool{
total: total,
concurrent: concurrent,
tasks: make(chan func()),
done: make(chan bool, total),
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment