mirror of
https://github.com/metabarcoding/obitools4.git
synced 2025-06-29 16:20:46 +00:00
152 lines
2.3 KiB
Go
152 lines
2.3 KiB
Go
![]() |
package obiblackboard
|
||
|
|
||
|
import (
|
||
|
"slices"
|
||
|
"sync"
|
||
|
|
||
|
"git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obiutils"
|
||
|
)
|
||
|
|
||
|
type Runner struct {
|
||
|
Run func(*Task) *Task
|
||
|
To string
|
||
|
}
|
||
|
|
||
|
type Blackboard struct {
|
||
|
Board map[int]Queue
|
||
|
BoardLock *sync.Mutex
|
||
|
Runners map[string]Runner
|
||
|
Running *obiutils.Counter
|
||
|
Size int
|
||
|
}
|
||
|
|
||
|
func NewBlackBoard(size int) *Blackboard {
|
||
|
board := make(map[int]Queue, 0)
|
||
|
runners := make(map[string]Runner, 0)
|
||
|
|
||
|
if size < 2 {
|
||
|
size = 2
|
||
|
}
|
||
|
|
||
|
bb := &Blackboard{
|
||
|
Board: board,
|
||
|
BoardLock: &sync.Mutex{},
|
||
|
Runners: runners,
|
||
|
Running: obiutils.NewCounter(),
|
||
|
Size: size,
|
||
|
}
|
||
|
|
||
|
for i := 0; i < size; i++ {
|
||
|
bb.PushTask(NewInitialTask())
|
||
|
}
|
||
|
|
||
|
return bb
|
||
|
}
|
||
|
|
||
|
func (bb *Blackboard) RegisterRunner(from, to string, runner func(*Task) *Task) {
|
||
|
bb.Runners[from] = Runner{
|
||
|
Run: runner,
|
||
|
To: to}
|
||
|
}
|
||
|
|
||
|
func (bb *Blackboard) MaxQueue() Queue {
|
||
|
max_priority := -1
|
||
|
max_queue := Queue(nil)
|
||
|
for priority, queue := range bb.Board {
|
||
|
if priority > max_priority {
|
||
|
max_queue = queue
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return max_queue
|
||
|
}
|
||
|
|
||
|
func (bb *Blackboard) PopTask() *Task {
|
||
|
bb.BoardLock.Lock()
|
||
|
defer bb.BoardLock.Unlock()
|
||
|
|
||
|
q := bb.MaxQueue()
|
||
|
|
||
|
if q != nil {
|
||
|
next_task := (*q)[0]
|
||
|
(*q) = (*q)[1:]
|
||
|
if len(*q) == 0 {
|
||
|
delete(bb.Board, next_task.Priority)
|
||
|
}
|
||
|
return next_task
|
||
|
}
|
||
|
|
||
|
return (*Task)(nil)
|
||
|
}
|
||
|
|
||
|
func (bb *Blackboard) PushTask(task *Task) {
|
||
|
bb.BoardLock.Lock()
|
||
|
defer bb.BoardLock.Unlock()
|
||
|
|
||
|
if task != nil {
|
||
|
priority := task.Priority
|
||
|
queue, ok := bb.Board[priority]
|
||
|
|
||
|
if !ok {
|
||
|
queue = NewQueue()
|
||
|
bb.Board[priority] = queue
|
||
|
}
|
||
|
|
||
|
*queue = slices.Grow(*queue, 1)
|
||
|
*queue = append((*queue), task)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (bb *Blackboard) Run() {
|
||
|
|
||
|
ctask := make(chan *Task)
|
||
|
lock := &sync.WaitGroup{}
|
||
|
|
||
|
launcher := func() {
|
||
|
for task := range ctask {
|
||
|
runner, ok := bb.Runners[task.Role]
|
||
|
|
||
|
if ok {
|
||
|
task = runner.Run(task)
|
||
|
if task != nil {
|
||
|
task.Role = runner.To
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bb.PushTask(task)
|
||
|
bb.Running.Dec()
|
||
|
}
|
||
|
|
||
|
lock.Done()
|
||
|
}
|
||
|
|
||
|
parallel := bb.Size - 1
|
||
|
lock.Add(parallel)
|
||
|
|
||
|
for i := 0; i < parallel; i++ {
|
||
|
go launcher()
|
||
|
}
|
||
|
|
||
|
go func() {
|
||
|
|
||
|
for {
|
||
|
bb.Running.Inc()
|
||
|
task := bb.PopTask()
|
||
|
|
||
|
if task != nil {
|
||
|
ctask <- task
|
||
|
} else {
|
||
|
bb.Running.Dec()
|
||
|
if bb.Running.Value() <= 0 {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
close(ctask)
|
||
|
}()
|
||
|
|
||
|
lock.Wait()
|
||
|
}
|