golang: semaphore pattern

Without semaphore, without limiter

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "sync"
)

const (
    count   = 200
    baseUrl = "https://jsonplaceholder.typicode.com/todos"
)

func main() {
    wg := sync.WaitGroup{}
    wg.Add(count)
    for i := 0; i < count; i++ {
        go func(i int) {
            defer wg.Done()
            getData(i)
        }(i)
    }
    wg.Wait()
}

func getData(index int) error {
    url := fmt.Sprintf("%s/%d", baseUrl, index)
    res, err := http.Get(url)
    if err != nil {
        return err
    }
    defer res.Body.Close()
    body, err := ioutil.ReadAll(res.Body)
    if err != nil {
        return err
    }
    fmt.Println(runtime.NumGoroutine())
    fmt.Println(index)
    fmt.Println(string(body))
    return nil
}

With channel like limiter

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "runtime"
    "sync"
)

const (
    count   = 200
    limiter = 10
    baseUrl = "https://jsonplaceholder.typicode.com/todos"
)

func main() {
    wg := sync.WaitGroup{}
    sem := make(chan bool, limiter)
    wg.Add(count)
    for i := 0; i < count; i++ {
        sem <- true
        go func(i int) {
            defer wg.Done()
            defer func() { <-sem }()
            getData(i)
        }(i)
    }
    wg.Wait()
}

func getData(index int) error {
    url := fmt.Sprintf("%s/%d", baseUrl, index)
    res, err := http.Get(url)
    if err != nil {
        return err
    }
    defer res.Body.Close()
    body, err := ioutil.ReadAll(res.Body)
    if err != nil {
        return err
    }
    fmt.Println(runtime.NumGoroutine())
    fmt.Println(index)
    fmt.Println(string(body))
    return nil
}

With semaphore like limiter

package main

import (
    "context"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "runtime"
    "sync"
    "golang.org/x/sync/semaphore"
)

const (
    count   = 200
    limiter = 10
    baseUrl = "https://jsonplaceholder.typicode.com/todos"
)

func main() {
    wg := sync.WaitGroup{}
    sem := semaphore.NewWeighted(int64(limiter))
    wg.Add(count)
    for i := 0; i < count; i++ {
        if err := sem.Acquire(context.Background(), 1); err != nil {
            log.Fatal(err)
        }
        go func(i int) {
            defer wg.Done()
            defer sem.Release(1)
            getData(i)
        }(i)
    }
    wg.Wait()
}

func getData(index int) error {
    url := fmt.Sprintf("%s/%d", baseUrl, index)
    res, err := http.Get(url)
    if err != nil {
        return err
    }
    defer res.Body.Close()
    body, err := ioutil.ReadAll(res.Body)
    if err != nil {
        return err
    }
    fmt.Println(runtime.NumGoroutine())
    fmt.Println(index)
    fmt.Println(string(body))
    return nil
}
Publikováno v Go