Documentation
¶
Overview ¶
async - a package that provides tools for parallel execution using built-in goroutines. Please note, because of the way goroutines work, execution is parallel, not concurrent! On top of existing async/await functionality, package also provides high-level functions like Map, Pool, etc.
Async / Await ¶
The most basic functionality of the package is async/await pattern. It allows you to run functions in parallel and wait for their completion.
Please note, that async functions are not concurrent, they are parallel. It's important because you still have to be careful with shared resources.
// Example of async function. func mult(n int) *async.Future[int] { return async.New(func() (int, error) { time.Sleep(time.Second) return n * 2, nil }) } // We will use this future to demonstrate resolving. ftr := mult(2) // We have multiple ways to handle future resolving. // One of them is to use Then/Catch methods. // Then is called on execution completion, Catch is called when future has an error. ftr.Then(func(val int) { fmt.Println("Resolved:", val) }).Catch(func(err error) { fmt.Println("Error:", err) }) // Another way is to use Await method. // It will block until future is resolved. val, err := ftr.Await() // We also have an async.Await function if you prefer functional style. val, err := async.Await(ftr)
Map / Filter / Pool ¶
The package provides high-level functions to work with collections, such as Map, Filter, and Pool.
Behavior of Map and Filter is similar to their counterparts in slice package. The difference is that they run functions in parallel. Please note, performance is usually lower than using slice package! Use them only if you know that cpu/io cost of a logic is higher than goroutines spin up cost.
// Example of Map function. results := async.Map(slice.Range(1, 1000), func(v int) int { return Workload(v) }) // Example of Filter function. results := async.Filter(slice.Range(1, 1000), func(v int) bool { return v < 500 })
In addition to Map and Filter, the package provides Pool function. It creates a pool of workers and channels for input and output.
// Task holds processing data, like id, input, and result. type Task struct { ID int Value int Result int } // Spin up a pool of 10 workers. in, out := async.Pool(10, func(v *Task) *Task { return Workload(v) }) // Send 1000 tasks to the pool. go func() { for i := 0; i < 1000; i++ { in <- &Task{ID: i, Value: i} } close(in) }() // Read results from the pool. // Out channel will be closed automatically on input channel close // and workers completion. for v := range out { fmt.Println(v.ID, v.Result) }
Index ¶
- func Await[T any](f *Future[T]) (T, error)
- func AwaitAll[T any](futures ...*Future[T]) ([]T, error)
- func AwaitRuntime(f ImplementsAwaitRuntime) (any, error)
- func Filter[T any](slice []T, fn func(v T) bool) []T
- func Map[T1 any, T2 any](slice []T1, fn func(v T1) T2) []T2
- func Pool[T1 any, T2 any](num int, worker func(v T1) T2) (chan T1, chan T2)
- type Future
- type ImplementsAwaitRuntime
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AwaitRuntime ¶
func AwaitRuntime(f ImplementsAwaitRuntime) (any, error)
AwaitRuntime is a runtime version of async.Await.
func Filter ¶
Filter returns filtered slice according to the given function. Same as slice.Filter, but executed in parallel. Useful for cases when comparison function becomes expensive.
Usage:
Filter(slice.Range(1, 1000), func(v int) bool { return v < 500 })
func Map ¶
Map returns a new slice with the results of applying the given function to each element in the given slice. Asynchronous version of slice.Map. Please note, it's not always faster! Goroutines allocation and synchronization have own cost.
Usage:
// Let's assume we have some workload in Workload function, which returns an integer. results := async.Map(slice.Range(1, 1000), func(v int) int { return Workload(v) })
func Pool ¶
Pool creates i/o channels and spins up a pool of workers for it. To stop the pool, you have to close input channel. Output channel will be closed automatically on workers completion.
Please note, output order is not guaranteed! Use own wrapper if you need to identify output.
Usage:
// Task holds processing data, like id, input, and result. type Task struct { ID int Value int Result int } in, out := async.Pool(10, func(v *Task) *Task { return Workload(v) }) go func() { for i := 0; i < 1000; i++ { in <- &Task{ID: i, Value: i} } close(in) }() for v := range out { fmt.Println(v.ID, v.Result) }
Types ¶
type Future ¶
type Future[T any] struct { // contains filtered or unexported fields }
Future is an execution result of an asynchronous function that returns immediately, without locking execution thread. To lock execution and wait for result, use .Await() method or async.Await() function. As an alternative you can use a syntax similar to JavaScript Promise, using .Then() and .Catch() methods.
Usage:
// Let's assume we have a future object in "ftr" variable. // We can lock execution and wait for a result with .Await() res, err := ftr.Await() // Or, we can use async.Await() res, err := async.Await(ftr) // Or, we can avoid locking execution and provide then/catch // functions to handle execution results. ftr.Then(func(val string) { println(val) }).Catch(func(err error) { println(err.Error()) })
func (*Future[T]) Await ¶
Await for a future object results.
Usage:
// Let's assume we have a future object in "ftr" variable. res, err := ftr.Await()
func (*Future[T]) AwaitRuntime ¶
AwaitRuntime is a runtime version of .Await()
Usage:
// Let's assume we have a future object in "ftr" variable. // Result will be stored as "any" type, so you'll need to cast it. res, err := ftr.AwaitRuntime()
func (*Future[T]) Catch ¶
Catch accepts a function, that will be executed on future execution error.
Usage:
// Let's assume we have a future object of string in "ftr" variable. ftr.Catch(func(err error) { println(err.Error()) })
func (*Future[T]) MarshalJSON ¶
MarshalJSON implements future marshalling.
func (*Future[T]) Then ¶
Then accepts a function, that will be executed on future work completion.
Usage:
// Let's assume we have a future object of string in "ftr" variable. ftr.Then(func(v string) { println(v) })
func (*Future[T]) UnmarshalJSON ¶
UnmarshalJSON implements future unmarshalling.
type ImplementsAwaitRuntime ¶
Interface for runtime await.