Skip to content

Instantly share code, notes, and snippets.

@simcap
Created May 11, 2017 17:37
Show Gist options
  • Select an option

  • Save simcap/4f04e90508aac186e5babfeecf9aa17a to your computer and use it in GitHub Desktop.

Select an option

Save simcap/4f04e90508aac186e5babfeecf9aa17a to your computer and use it in GitHub Desktop.
Run interdependent tasks asynchronously
package main
import (
"fmt"
"sync"
"time"
)
func main() {
cmds := []*cmd{
&cmd{id: 1, line: "executed 1", wait: []int{}},
&cmd{id: 2, line: "executed 2", wait: []int{5,4}},
&cmd{id: 3, line: "executed 3", wait: []int{5}},
&cmd{id: 4, line: "executed 4", wait: []int{3, 1}},
&cmd{id: 5, line: "executed 5", wait: []int{4}},
}
run(cmds)
}
func run(cmds []*cmd) {
var wg sync.WaitGroup
done := make(chan int, len(cmds))
var waiting []*waitingCmd
for _, c := range cmds {
wc := &waitingCmd{c: c, wait: make(chan int, len(cmds))}
waiting = append(waiting, wc)
}
go func() {
for {
select {
case d, ok := <-done:
if !ok {
return
}
for _, c := range waiting {
c.wait <- d
}
}
}
}()
for _, wc := range waiting {
wg.Add(1)
go func(wc *waitingCmd) {
defer wg.Done()
wc.exec(done)
}(wc)
}
wg.Wait()
close(done)
}
type waitingCmd struct {
c *cmd
wait chan int
}
func (wc *waitingCmd) exec(done chan int) {
var dones []int
if len(wc.c.wait) > 0 {
for {
select {
case d := <-wc.wait:
dones = append(dones, d)
fmt.Printf("(cmd: %d, wait for %v) dones: %v\n", wc.c.id, wc.c.wait, dones)
if allDone(wc.c, dones) {
fmt.Printf("(cmd: %d) Awaiting finished\n", wc.c.id)
wc.c.exec()
done <- wc.c.id
return
}
}
}
} else {
wc.c.exec()
done <- wc.c.id
}
}
func allDone(c *cmd, dones []int) bool {
for _, w := range c.wait {
found := false
for _, d := range dones {
if w == d {
found = true
}
}
if found == false {
return false
}
}
return true
}
type cmd struct {
id int
line string
async bool
wait []int
}
func (c *cmd) exec() {
time.Sleep(1 * time.Second)
fmt.Println(c.line)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment