semaphore

package module
v0.0.0-...-76b2cf3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 2, 2022 License: MIT Imports: 1 Imported by: 3

README

semaphore

semaphore is a package providing a "counting semaphore".

It has an API similar to sync.WaitGroup, but instead of allowing unlimited Add() calls, when it reaches the configured amount, it will block until another has been released.

It's "thread-safe" (or "goroutine-safe"), so can be used between different goroutines without any extra code.

It's ideal in situations when you want concurrency, but want to avoid running too many things at once. The exact amount you will want to set as a limit will depend; for CPU-bound tasks, you might want to set it to runtime.NumCPU(), or something similar, however for disk or network I/O bound tasks a limit of thousands or tens of thousands may be more appropriate. Benchmark to find what works best for your workload!

Be careful when using more than one Add() call per task. If you use more than one, without carefully controlling when you call Done() to release them, you can easily find yourself in a deadlock!

Documentation

Overview

Package semaphore provides a semaphore/queuing implementation based on https://pauladamsmith.com/blog/2016/04/max-clients-go-net-http.html

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Semaphore

type Semaphore struct {
	// contains filtered or unexported fields
}
Example
package main

import (
	"fmt"
	"time"

	"github.com/jamesrr39/semaphore"
)

func main() {
	s := semaphore.NewSemaphore(4)
	for i := 0; i < 22; i++ {
		s.Add()
		go func(i int) {
			defer func() {
				s.Done()
				fmt.Printf("finished %d\n", i)
			}()
			fmt.Printf("running: %d\n", i)
			time.Sleep(time.Second * time.Duration(i))
		}(i)
	}
	s.Wait()
}
Output:

Example (WithErrorHandling)

ExampleSemaphoreWithErrorHandling shows an example with some error handling that avoids doing the hard work if there has already been an error

package main

import (
	"fmt"
	"os"

	"github.com/jamesrr39/semaphore"
)

func main() {
	s := semaphore.NewSemaphore(4)
	var outerErr error
	for i := 0; i < 3; i++ {
		s.Add()
		go func(i int) {
			defer s.Done()
			if outerErr != nil {
				// skip the hard work below if there has previously been an error
				return
			}

			file, err := os.Open(fmt.Sprintf("myfile%d.txt", i))
			if err != nil {
				outerErr = err
				return
			}
			defer file.Close()

			// do some hard work with the file here...
		}(i)
	}
	s.Wait()
	if outerErr != nil {
		// handle error here
	}
}
Output:

func NewSemaphore

func NewSemaphore(maxConcurrentOps uint) *Semaphore

func (*Semaphore) Add

func (s *Semaphore) Add()

func (*Semaphore) CurrentlyRunning

func (s *Semaphore) CurrentlyRunning() int

func (*Semaphore) Done

func (s *Semaphore) Done()

func (*Semaphore) Wait

func (s *Semaphore) Wait()

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL