Documentation
¶
Overview ¶
Package async is a package to provide simplistic asynchronous routines for the masses.
Index ¶
- func Filter(data interface{}, routine Routine, callbacks ...Done)
- func FilterParallel(data interface{}, routine Routine, callbacks ...Done)
- func Map(data interface{}, routine Routine, callbacks ...Done)
- func MapParallel(data interface{}, routine Routine, callbacks ...Done)
- func Parallel(routines []Routine, callbacks ...Done)
- func Series(routines []Routine, callbacks ...Done)
- func SeriesParallel(routines []Routine, callbacks ...Done)
- func Waterfall(routines []Routine, callbacks ...Done)
- type Done
- type Event
- type Events
- func (e Events) Clear(name ...string) Events
- func (e Events) Emit(name string, args ...interface{}) Events
- func (e Events) Get(name string) Event
- func (e Events) Length(name string) int
- func (e Events) On(name string, callbacks ...interface{}) Events
- func (e Events) Once(name string, callbacks ...interface{}) Events
- func (e Events) Times(name string, times int, callbacks ...interface{}) Events
- type List
- func (l *List) Add(routine Routine) (*List, *list.Element)
- func (l *List) Multiple(routines ...Routine) (*List, []*list.Element)
- func (l *List) Remove(element *list.Element) (*List, Routine)
- func (l *List) RunParallel(callbacks ...Done)
- func (l *List) RunSeries(callbacks ...Done)
- func (l *List) RunSeriesParallel(callbacks ...Done)
- func (l *List) RunWaterfall(callbacks ...Done)
- type Routine
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Filter ¶
Filter allows you to filter out information from a slice in Waterfall mode.
You must call the Done function with false as its first argument if you do not want the data to be present in the results. No other arguments will affect the performance of this function. When calling the Done function, an error will cause the filtering to immediately exit.
For example, take a look at one of the tests for this function:
func TestFilterString(t *testing.T) { str := []string{ "test1", "test2", "test3", "test4", "test5", } expects := []string{ "test1", "test2", "test4", "test5", } mapper := func(done async.Done, args ...interface{}) { Status("Hit string") Status("Args: %+v\n", args) if args[0] == "test3" { done(nil, false) return } done(nil, true) } final := func(err error, results ...interface{}) { Status("Hit string end") Status("Results: %+v\n", results) for i := 0; i < len(results); i++ { if results[i] != expects[i] { t.Errorf("Did not filter correctly.") break } } } async.Filter(str, mapper, final) }
Each Routine function will be passed the current value and its index the slice for its arguments.
func FilterParallel ¶
FilterParallel allows you to filter out information from a slice in Parallel mode.
You must call the Done function with false as its first argument if you do not want the data to be present in the results. No other arguments will affect the performance of this function.
If there is an error, any further results will be discarded but it will not immediately exit. It will continue to run all of the other Routine functions that were passed into it. This is because by the time the error is sent, the goroutines have already been started. At this current time, there is no way to cancel a sleep timer in Go.
For example, take a look at one of the tests for this function:
func TestFilterStringParallel(t *testing.T) { str := []string{ "test1", "test2", "test3", "test4", "test5", } expects := []string{ "test1", "test2", "test4", "test5", } mapper := func(done async.Done, args ...interface{}) { Status("Hit string") Status("Args: %+v\n", args) if args[0] == "test3" { done(nil, false) return } done(nil, true) } final := func(err error, results ...interface{}) { Status("Hit string end") Status("Results: %+v\n", results) for i := 0; i < len(results); i++ { if results[i] != expects[i] { t.Errorf("Did not filter correctly.") break } } } async.FilterParallel(str, mapper, final) }
Each Routine function will be passed the current value and its index the slice for its arguments.
The output of filtering in Parallel mode cannot be guaranteed to stay in the same order, due to the fact that it may take longer to process some things in your filter routine. If you need the data to stay in the order it is in, use Filter instead to ensure it stays in order.
func Map ¶
Map allows you to manipulate data in a slice in Waterfall mode.
Each Routine will be called with the value and index of the current position in the slice. When calling the Done function, an error will cause the mapping to immediately exit. All other arguments are sent back as the replacement for the current value.
For example, take a look at one of the tests for this function:
func TestMapInt(t *testing.T) { ints := []int{1, 2, 3, 4, 5} expects := []int{2, 4, 6, 8, 10} mapper := func(done async.Done, args ...interface{}) { Status("Hit int") Status("Args: %+v\n", args) done(nil, args[0].(int)*2) } final := func(err error, results ...interface{}) { Status("Hit int end") Status("Results: %+v\n", results) for i := 0; i < len(results); i++ { if results[i] != expects[i] { t.Errorf("Did not map correctly.") break } } } async.Map(ints, mapper, final) }
func MapParallel ¶
MapParallel allows you to manipulate data in a slice in Parallel mode.
Each Routine will be called with the value and index of the current position in the slice. When calling the Done function, arguments are sent back as the replacement for the current value.
If there is an error, any further results will be discarded but it will not immediately exit. It will continue to run all of the other Routine functions that were passed into it. This is because by the time the error is sent, the goroutines have already been started. At this current time, there is no way to cancel a sleep timer in Go.
For example, take a look at one of the tests for this function:
func TestMapStringParallel(t *testing.T) { str := []string{ "test", "test2", "test3", "test4", "test5", } expects := []string{ "test1", "test2", "test3", "test4", "test5", } mapper := func(done async.Done, args ...interface{}) { Status("Hit string") Status("Args: %+v\n", args) if args[1] == 0 { done(nil, "test1") return } done(nil, args[0]) } final := func(err error, results ...interface{}) { Status("Hit string end") Status("Results: %+v\n", results) for i := 0; i < len(results); i++ { if results[i] != expects[i] { t.Errorf("Did not map correctly.") break } } } async.MapParallel(str, mapper, final) }
The output of mapping in Parallel mode cannot be guaranteed to stay in the same order, due to the fact that it may take longer to process some things in your map routine. If you need the data to stay in the order it is in, use Map instead to ensure it stays in order.
func Parallel ¶
Parallel is a shorthand function to List.RunParallel without having to manually create a new list, add the routines, etc.
func Series ¶
Series is a shorthand function to List.RunSeries without having to manually create a new list, add the routines, etc.
func SeriesParallel ¶
SeriesParallel is a shorthand function to List.RunSeriesParallel without having to manually create a new list, add the routines, etc.
Types ¶
type Done ¶
type Done func(error, ...interface{})
Done types are used for shorthand definitions of the functions that are passed into each Routine to show that the Routine has completed.
An example a Done function would be:
func ImDone(err error, args ...interface{}) { if err != nil { // Handle the error your Routine returned. return } // There wasn't an error returned your Routine! Do what you want with // the args. }
type Event ¶
Event is a map of functions to use for a single event. The integer is the frequency of calls that the function should make.
type Events ¶
Events is a map that is used for containing everything related to the events. It stores the name of the event, functions for the event, and number of times the function should be called when the event is triggered.
All you need to do to create an event list is:
events := make(async.Events)
All event commands that return Events can be chained together. For example:
events.On("myevent", func() { println("Called myevent") }).On("myevent2", func(msg string) { fmt.Printf("Called myevent2 with message: %s\n", msg) }).Emit("myevent").Emit("myevent2", "Testing")
You can return an error from a function and it will be emitted as an error event. For example:
events.On("error", func(err error) { fmt.Printf("Error: %s", err) }).On("myevent", func() error { return fmt.Errorf("Some error message") }).Emit("myevent")
It's also easily inheritable by other structures. For example:
type MyStruct struct { async.Events } m := MyStruct{make(async.Events)} m.On("myevent", func() { println("Called myevent") }).Emit("myevent")
When you are defining your event, all function calls within that event must be in the same format.
For instance, this will work fine:
events.On("myevent", func() {}, func() {})
However, this will NOT work:
events.On("myevent", func() {}, func (msg string) {})
If you were to try this second example, and then try to .Emit("myevent", "message"), you would get an error from reflect saying that there is too many arguments for the first function. If you were to try .Emit("myevent"), you would get an error that there are not enough arguments because of the second function expecting an argument.
func (Events) Clear ¶
Clear all events out of the event list. You can supply optional names for the events to be cleared.
For instance:
events.On("test", func() {}).On("test2", func() {}).Emit("test").Clear("test")
Returns the list of events for chaining commands.
func (Events) Emit ¶
Emit an event. Arguments are optional. Each event will be ran as a Series.
For example:
events := make(async.Events) events.On("myevent", func() { println("Emitted myevent") }) events.Emit("myevent")
With arguments:
events := make(async.Events) events.On("myevent", func(msg string) { fmt.Printf("Message: %s\n", msg) }) events.Emit("myevent", "Testing")
Returns the list of events for chaining commands.
func (Events) Get ¶
Get Event map of functions and frequencies for the named event. This is just a convenience function. This data could also be accessed by the normal mapping methods.
For instance:
fmt.Printf("Events for myevent: %+v\n", e["myevent"])
func (Events) Length ¶
Length gets the length of the Event map of functions and frequencies for the named event. This is just a convenience function. This data could also be accessed by the normal mapping methods.
For instance:
fmt.Printf("Length: %d", len(e["myevent"]))
func (Events) On ¶
On adds an event to be called forever.
This is equal to calling Times with -1 as the number of times to run the event. More documentation can be found on the Times function.
Returns the list of events for chaining commands.
func (Events) Once ¶
Once adds an event to be called only once.
This is equal to calling Times with 1 as the number of times to run the event. More documentation can be found on the Times function.
Returns the list of events for chaining commands.
type List ¶
List is used to contain the Routine functions to be processed
This list inherits https://godoc.org/container/list and contains all of the functionality that it contains, with a minor tweak to Remove. Instead of Remove returning the element, it returns our routine. This is used to ensure that our Routine is removed from the list before it's ran, and therefore isn't able to be called again.
func (*List) Remove ¶
Remove deletes a Routine element from the current list
An example of removing a Routine would be:
err, routine := l.Remove(l.Front())
func (*List) RunParallel ¶
RunParallel will run all of the Routine functions from the current list in parallel mode.
All of the arguments returned in a Routine's Done function will be combined and returned in the callbacks that are provided.
If there is an error, any further results will be discarded but it will not immediately exit. It will continue to run all of the other Routine functions that were passed into it. This is because by the time the error is sent, the goroutines have already been started. At this current time, there is no way to cancel a sleep timer in Go.
For example:
async.Parallel([]async.Routine{ func(done async.Done, args ...interface{}) { time.Sleep(20 * time.Second) done(nil, "Won't trigger the callbacks because error has been sent") }, func(done async.Done, args ...interface{}) { done(fmt.Errorf("Test error")) } }, func(err error, results ...interface{}) { if err != nil { fmt.Printf("Error: %s", err) return } fmt.Printf("Args: %s", args) })
If you were to run this example, you would see the error happen immediately. However, you would also notice that the program doesn't immediately exit. That is because it is still waiting for responses that it silently discards, since an error has already occurred.
func (*List) RunSeries ¶
RunSeries will run all of the Routine functions in a series effect.
If there is an error, series will immediately exit and trigger the callbacks with the error.
There are no arguments passed between the routines that are used in series. It is just for commands that need to run asynchronously without seeing the results of its previous routine.
For example, take a look at one of the tests for this function:
func TestSeries(t *testing.T) { counter := 0 Status("Calling Series") async.Series([]async.Routine{ func(done async.Done, args ...interface{}) { Status("Increasing counter...") counter++ done(nil) }, func(done async.Done, args ...interface{}) { Status("Increasing counter...") counter++ done(nil) }, func(done async.Done, args ...interface{}) { Status("Increasing counter...") counter++ done(nil) }, func(done async.Done, args ...interface{}) { Status("Increasing counter...") counter++ done(nil) }, }, func(err error, results ...interface{}) { if err != nil { t.Errorf("Unexpected error: %s", err) return } if counter != 4 { t.Errorf("Not all routines were completed.") return } Status("Counter: %d", counter) }) }
func (*List) RunSeriesParallel ¶
RunSeriesParallel all of the Routine functions in a series effect, and in parallel mode.
If there is an error, any further results will be discarded but it will not immediately exit. It will continue to run all of the other Routine functions that were passed into it. This is because by the time the error is sent, the goroutines have already been started. At this current time, there is no way to cancel a sleep timer in Go.
There are no arguments passed between the routines that are used in series. It is just for commands that need to run asynchronously without seeing the results of its previous routine.
For example, take a look at one of the tests for this function:
func TestSeriesParallel(t *testing.T) { counter := 0 Status("Calling Series") async.SeriesParallel([]async.Routine{ func(done async.Done, args ...interface{}) { Status("Increasing counter...") counter++ done(nil) }, func(done async.Done, args ...interface{}) { Status("Increasing counter...") counter++ done(nil) }, func(done async.Done, args ...interface{}) { Status("Increasing counter...") counter++ done(nil) }, func(done async.Done, args ...interface{}) { Status("Increasing counter...") counter++ done(nil) }, }, func(err error, results ...interface{}) { if err != nil { t.Errorf("Unexpected error: %s", err) return } if counter != 4 { t.Errorf("Not all routines were completed.") return } Status("Counter: %d", counter) }) }
func (*List) RunWaterfall ¶
RunWaterfall runs all of the Routine functions in a waterfall effect.
The arguments of the previous Routine function will be passed into the next Routine function. The final result provided to the callbacks will be the result of the last Routine function.
If there is an error, waterfall will immediately exit and trigger the callbacks with the error.
type Routine ¶
type Routine func(Done, ...interface{})
Routine types are used for shorthand definitions of the functions that are actually ran when calling Parallel, Waterfall, etc.
An example of a Routine function would be:
func MyRoutine(done async.Done, args ...interface{}) { // Do something in your routine and then call its done function. done(nil, "arg1", "arg2", "arg3") }