Documentation
¶
Overview ¶
Package async provides constructs for various asynchronous patterns.
Index ¶
Examples ¶
Constants ¶
const (
PanicSetOnImmediateFuture = "you cannot set a value on an immediate future"
)
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type CountingSemaphore ¶
type CountingSemaphore interface {
// Size returns the total number of tokens available withing this CountingSemaphore.
Size() int32
// Acquire attempts to acquire an amount of tokens from the semaphore, waiting until it is successful.
Acquire(count int32)
// TryAcquire attempts to acquire an amount of tokens from the semaphore and returns whether
// it was successful or not.
TryAcquire(count int32) bool
// Release attempts to return a certain amount of tokens to the semaphore, waiting until it is successful.
Release(count int32)
// TryRelease attempts to return a certain amount of tokens to the semaphore and returns whether
// it was successful or not.
TryRelease(count int32) bool
}
CountingSemaphore can be used to limit the amount of in-flight processes / tasks.
Example ¶
// we create an input and output channel for work needing to be done
inCh := make(chan string, 128)
outCh := make(chan int, 128)
// we want a max of 10 in-flight processes
s := async.NewCountingSemaphore(10)
// we create more workers than tokens available
for i := 0; i < 100; i++ {
go func() {
for {
// acquire a token, waiting until one is available
s.Acquire(1)
// consume from the input channel
v, ok := <-inCh
if !ok {
// channel was closed
return
}
// do some work and produce an output value
outCh <- len(v)
// you need to be careful about releasing, if possible perform it with defer
s.Release(1)
}
}()
}
// generate some work and put it into the work queue
// ...
// ...
func NewCountingSemaphore ¶
func NewCountingSemaphore(size int32) CountingSemaphore
NewCountingSemaphore creates a new semaphore with specified amount of available tokens.
type Future ¶
type Future[T any] interface { // Get returns a response channel of size 1 for receiving the future value. // If the value has already been set it will already be available within the return channel. Get() <-chan T // Set sets the return value and notifies consumers. Consumers are notified once only, // with the return value indicating if Set was successful or not. Set(value T) bool }
Future represents a value of type T that will be set at some time in the future.
Example (Basic) ¶
// create a string future
f := async.NewFuture[string]()
// create a consumer channel
ch := f.Get()
go func() {
println(fmt.Sprintf("Value: %s", <-ch))
}()
// set the value
f.Set("hello")
Example (Multiple) ¶
// create some futures
foo := async.NewFuture[string]()
bar := async.NewFuture[string]()
// compute in the background
go func() {
foo.Set("foo")
}()
go func() {
foo.Set("bar")
}()
// wait for their results
println(<-foo.Get())
println(<-bar.Get())
Example (Select) ¶
// create some futures
foo := async.NewFuture[string]()
bar := async.NewFuture[string]()
// compute their values in the background
go func() {
foo.Set("foo")
}()
go func() {
bar.Set("bar")
}()
// create some consumer channels
fooCh := foo.Get()
barCh := bar.Get()
// wait with timeout
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
var result []string
finished := false
for {
select {
case <-ctx.Done():
fmt.Println("timeout")
finished = true
case v, ok := <-fooCh:
if ok {
result = append(result, v)
}
finished = len(result) == 2
case v, ok := <-barCh:
if ok {
result = append(result, v)
}
finished = len(result) == 2
}
if finished {
// break out of the loop
break
}
}
// print all the results
fmt.Println(result)
func NewFutureImmediate ¶
NewFutureImmediate creates a future of type T that has a value that is already set.
Example ¶
f := async.NewFutureImmediate("hello")
println(<-f.Get())
type Result ¶
type Result[T any] interface { // Unwrap deconstructs the contents of this Result into a tuple. Unwrap() (T, error) }
Result is a simple wrapper for representing a value or an error.
func NewResult ¶
NewResult creates a result instance with a provided value and error. It's sometimes more convenient to instantiate like this when implementing library code.
Example ¶
result := async.NewResultValue[string]("success")
v, _ := result.Unwrap()
println(v)
func NewResultErr ¶
NewResultErr creates a failed result.
Example ¶
result := async.NewResultErr[string](errors.New("failure"))
_, err := result.Unwrap()
panic(err)
func NewResultValue ¶
NewResultValue creates a successful result.