Skip to content

pieterclaerhout/go-waitgroup

Repository files navigation

go-waitgroup

Build Status Go Report Card Documentation license GitHub version GitHub issues

How to use

An package that allows you to use the constructs of a sync.WaitGroup to create a pool of goroutines and control the concurrency.

Using it is just like a normal sync.WaitGroup. The only difference is the initialisation. When you use waitgroup.NewWaitGroup, you have the option to specify it's size.

Any int which is bigger than 0 will limit the number of concurrent goroutines. If you specify -1 or 0, all goroutines will run at once (just like a plain sync.WaitGroup).

package main

import (
    "fmt"
    "net/http"

    "github.com/pieterclaerhout/go-waitgroup"
)

func main() {
    
    urls := []string{
        "https://www.easyjet.com/",
        "https://www.skyscanner.de/",
        "https://www.ryanair.com",
        "https://wizzair.com/",
        "https://www.swiss.com/",
    }

    wg := waitgroup.NewWaitGroup(3)

	for _, url := range urls {
		wg.BlockAdd()
		go func(url string) {
			defer wg.Done()
			fmt.Printf("%s: checking\n", url)
			res, err := http.Get(url)
			if err != nil {
				fmt.Println("Error: %v")
			} else {
				defer res.Body.Close()
				fmt.Printf("%s: result: %v\n", url, err)
			}
		}(url)
	}

    wg.Wait()
    fmt.Println("Finished")

}

Using closures

There is also a way to use function closures to make it even more readable:

package main

import (
	"fmt"
	"net/http"

	"github.com/pieterclaerhout/go-waitgroup"
)

func main() {

	urls := []string{
		"https://www.easyjet.com/",
		"https://www.skyscanner.de/",
		"https://www.ryanair.com",
		"https://wizzair.com/",
		"https://www.swiss.com/",
	}

	wg := waitgroup.NewWaitGroup(3)

	for _, url := range urls {

		urlToCheck := url
		wg.Add(func() {
			fmt.Printf("%s: checking\n", urlToCheck)
			res, err := http.Get(urlToCheck)
			if err != nil {
				fmt.Println("Error: %v")
			} else {
				defer res.Body.Close()
				fmt.Printf("%s: result: %v\n", urlToCheck, err)
			}
		})

	}

	wg.Wait()
	fmt.Println("Finished")

}

Handling errors

If you want to handle errors, there is also an ErrorGroup. This uses the same principles as a normal WaitGroup with a small twist.

First of all, you can only add functions which returns just an error.

Second, as soon as one of the queued items fail, the rest will be cancelled:

package main

import (
	"context"
	"fmt"
	"os"

	"github.com/pieterclaerhout/go-waitgroup"
)

func main() {

	ctx := context.Background()

	wg, ctx := waitgroup.NewErrorGroup(ctx, tc.size)
	if err != nil {
		fmt.Println("Error: %v")
		os.Exit(1)
	}

	wg.Add(func() error {
		return nil
	})

	wg.Add(func() error {
		return errors.New("An error occurred")
	})

	if err := wg.Wait(); err != nil {
		fmt.Println("Error: %v")
		os.Exit(1)
	}

}

You can also add multiple functions in one step:

package main

import (
	"context"
	"errors"
	"fmt"
	"os"

	"github.com/pieterclaerhout/go-waitgroup"
)

func main() {

	ctx := context.Background()

	wg, ctx := waitgroup.NewErrorGroup(ctx, tc.size)
	if err != nil {
		fmt.Println("Error: %v")
		os.Exit(1)
	}

	wg.Add(
		func() error {
			return nil
		},
		func() error {
			return errors.New("An error occurred")
		},
	)

	if err := wg.Wait(); err != nil {
		fmt.Println("Error: %v")
		os.Exit(1)
	}

}

About

A sync.WaitGroup with error handling and concurrency control

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •  
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy