Answer the question
In order to leave comments, you need to log in
How to implement a run queue of goroutines?
Good afternoon! The task requires to implement a request execution queue.
In general, the situation is as follows. The web service accepts a json array of functions to be executed. The array itself is very similar to JSON-RPC with the addition of one more propertywait
[
{
"method": "controller:method1",
"params": {},
"id": 1
},
{
"method": "controller:method2",
"params": {},
"id": 2,
"wait": 1
}
]
package main
import (
"fmt"
"sync"
"time"
)
type chain struct {
Req *req
Wait chan bool
Signal chan bool
IsWaiting bool
}
type req struct {
Method func()
ID int
W int
}
func main() {
chainigs := make(map[int]*chain)
var fncs []*req
r1 := &req{
Method: func1,
ID: 1,
W: 0,
}
r2 := &req{
Method: func2,
ID: 2,
W: 1,
}
r3 := &req{
Method: func3,
ID: 3,
W: 0,
}
fncs = append(fncs, r1, r2, r3)
for _, req := range fncs {
ch := &chain{}
ch.Req = req
signalChan := make(chan bool)
ch.Signal = signalChan
chainigs[req.ID] = ch
if waitChan, ok := chainigs[req.W]; ok {
ch.Wait = waitChan.Signal
ch.IsWaiting = true
} else {
ch.IsWaiting = false
}
chainigs[req.ID] = ch
}
var wg sync.WaitGroup
for _, schain := range chainigs {
wg.Add(1)
go func(c *chain) {
if c.IsWaiting {
select {
case <-c.Wait:
c.Req.Method()
wg.Done()
go func() {
c.Signal <- true
close(c.Signal)
}()
}
} else {
c.Req.Method()
wg.Done()
c.Signal <- true
}
}(schain)
}
wg.Wait()
}
func func1() {
time.Sleep(2 * time.Second)
fmt.Println("FORM 1")
}
func func2() {
fmt.Println("FROM 2")
}
func func3() {
time.Sleep(2 * time.Second)
fmt.Println("FROM 3")
}
chain
has two fields with channels Wait
and Signal
. Wait
- will hold the channel Signal
of another structure to be expected to execute. Well, then start in the goroutine cycle, and check if the chain should wait for the execution of another, then we are waiting for the signal. If not, then we simply execute the function and send a termination signal. With such an implementation, it is possible to build chains of calls, and in general the program works correctly. I'm wondering how correct this approach can be considered? Perhaps there are patterns that are much better and more beautiful for realizing this possibility?
Answer the question
In order to leave comments, you need to log in
Maybe it's more convenient for you to attach weightgroups to processes and run them all at the same time?
https://golang.org/pkg/sync/#WaitGroup
1. We push a weight group into the structure for each task, add(1) to it, and after execution we do Done().
2. For each dependent task, before execution, we do Wait () for the weight groups of those tasks that it must wait for.
3. ????
4. PROFIT!!!
I don’t know which is better, but I would sort it in order of dependency and execute the methods in turn.
[
{
"method": "controller:method1",
"params": {},
"id": 1
},
{
"method": "controller:method2",
"params": {},
"id": 2,
"wait": 1
},
{
"method": "controller:method2",
"params": {},
"id": 3,
"wait": 1
},
{
"method": "controller:method2",
"params": {},
"id": 4,
"wait": 2
}
{
"method": "controller:method2",
"params": {},
"id": 5
}
]
[
[
{
"method": "controller:method1",
"params": {},
"id": 1
},
{
"method": "controller:method2",
"params": {},
"id": 5
}
],
[
{
"method": "controller:method2",
"params": {},
"id": 2,
"wait": 1
},
{
"method": "controller:method2",
"params": {},
"id": 3,
"wait": 1
},
],
[
{
"method": "controller:method2",
"params": {},
"id": 4,
"wait": 2
}
]
]
for _, step := range steps {
for _, f : range step {
f.method(f.params)
}
}
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question