semaphore

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Mar 2, 2019 License: BSD-3-Clause Imports: 3 Imported by: 2

README

Semaphore

Build Status codecov License

A fork of golang/x/sync/semaphore that is also resizable.


This fork adds the ability to resize the semaphore in a concurrent-safe way.

  • Use semaphore.Resize(N) to resize the semaphore to a new absolute value N
  • Example
    sem := semaphore.NewWeighted(5)     // Semaphore size = 5
    result1 := sem.TryAcquire(10)       // returns false.
    sem.Resize(15)                      // Semaphore size now = 10
    result2 := sem.TryAcquire(10)       // returns true.
    fmt.Println(result1,result2)        // prints false \n true  
    
  • Added resize functionality has no impact on the semaphore performance according to benchmarks.
  • Tests for the newly added Resize() was also added.

Documentation

Overview

Package semaphore provides a weighted semaphore implementation.

Example (WorkerPool)

Example_workerPool demonstrates how to use a semaphore to limit the number of goroutines working on parallel tasks.

This use of a semaphore mimics a typical “worker pool” pattern, but without the need to explicitly shut down idle workers when the work is done.

package main

import (
	"context"
	"fmt"
	"log"
	"runtime"
)

// Example_workerPool demonstrates how to use a semaphore to limit the number of
// goroutines working on parallel tasks.
//
// This use of a semaphore mimics a typical “worker pool” pattern, but without
// the need to explicitly shut down idle workers when the work is done.
func main() {
	ctx := context.TODO()

	var (
		maxWorkers = runtime.GOMAXPROCS(0)
		sem        = NewWeighted(int64(maxWorkers))
		out        = make([]int, 32)
	)

	// Compute the output using up to maxWorkers goroutines at a time.
	for i := range out {
		// When maxWorkers goroutines are in flight, Acquire blocks until one of the
		// workers finishes.
		if err := sem.Acquire(ctx, 1); err != nil {
			log.Printf("Failed to acquire semaphore: %v", err)
			break
		}

		go func(i int) {
			defer sem.Release(1)
			out[i] = collatzSteps(i + 1)
		}(i)
	}

	// Acquire all of the tokens to wait for any remaining workers to finish.
	//
	// If you are already waiting for the workers by some other means (such as an
	// errgroup.Group), you can omit this final Acquire call.
	if err := sem.Acquire(ctx, int64(maxWorkers)); err != nil {
		log.Printf("Failed to acquire semaphore: %v", err)
	}

	fmt.Println(out)

}

// collatzSteps computes the number of steps to reach 1 under the Collatz
// conjecture. (See https://en.wikipedia.org/wiki/Collatz_conjecture.)
func collatzSteps(n int) (steps int) {
	if n <= 0 {
		panic("nonpositive input")
	}

	for ; n > 1; steps++ {
		if steps < 0 {
			panic("too many steps")
		}

		if n%2 == 0 {
			n /= 2
			continue
		}

		const maxInt = int(^uint(0) >> 1)
		if n > (maxInt-1)/3 {
			panic("overflow")
		}
		n = 3*n + 1
	}

	return steps
}
Output:
[0 1 7 2 5 8 16 3 19 6 14 9 9 17 17 4 12 20 20 7 7 15 15 10 23 10 111 18 18 18 106 5]

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Weighted

type Weighted struct {
	// contains filtered or unexported fields
}

Weighted provides a way to bound concurrent access to a resource. The callers can request access with a given weight.

func NewWeighted

func NewWeighted(n int64) *Weighted

NewWeighted creates a new weighted semaphore with the given maximum combined weight for concurrent access.

func (*Weighted) Acquire

func (s *Weighted) Acquire(ctx context.Context, n int64) error

Acquire acquires the semaphore with a weight of n, blocking until resources are available or ctx is done. On success, returns nil. On failure, returns ctx.Err() and leaves the semaphore unchanged.

If ctx is already done, Acquire may still succeed without blocking.

func (*Weighted) Current

func (s *Weighted) Current() int64

Current returns the current size of semaphore. Returned value may instantly change after/during call. use for diagnostic and health-checking only.

func (*Weighted) Release

func (s *Weighted) Release(n int64)

Release releases the semaphore with a weight of n.

func (*Weighted) Resize

func (s *Weighted) Resize(n int64)

Resize semaphore.

func (*Weighted) Size

func (s *Weighted) Size() int64

Size returns the maximum size of semaphore. Returned value may instantly change after/during call. use for diagnostic and health-checking only.

func (*Weighted) TryAcquire

func (s *Weighted) TryAcquire(n int64) bool

TryAcquire acquires the semaphore with a weight of n without blocking. On success, returns true. On failure, returns false and leaves the semaphore unchanged.

func (*Weighted) Waiters

func (s *Weighted) Waiters() int

Waiters returns the number of currently waiting Acquire calls. Returned value may instantly change after/during call. use for diagnostic and health-checking only.

Jump to

Keyboard shortcuts

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