github.com/coyove/common@v0.0.0-20240403014525-f70e643f9de8/burst/burst.go (about) 1 package burst 2 3 type task struct { 4 in interface{} 5 out chan interface{} 6 } 7 8 type Manager struct { 9 batch chan *task 10 QueueSize int 11 BatchSize int 12 NumWorkers int 13 F func(in []interface{}) (out []interface{}) 14 } 15 16 func (m *Manager) Start() { 17 if m.F == nil { 18 panic("F is nil") 19 } 20 if m.QueueSize == 0 { 21 m.QueueSize = 1024 22 } 23 if m.NumWorkers == 0 { 24 m.NumWorkers = 1 25 } 26 if m.BatchSize == 0 { 27 m.BatchSize = 16 28 } 29 30 m.batch = make(chan *task, m.QueueSize) 31 for i := 0; i < m.NumWorkers; i++ { 32 go func() { 33 tasks := []*task{} 34 blocking := false 35 36 for { 37 if blocking { 38 t := <-m.batch 39 tasks = append(tasks, t) 40 } else { 41 for exit := false; !exit; { 42 select { 43 case t := <-m.batch: 44 tasks = append(tasks, t) 45 if len(tasks) >= m.BatchSize { 46 exit = true 47 } 48 default: 49 exit = true 50 } 51 } 52 } 53 54 if len(tasks) == 0 { 55 blocking = true 56 continue 57 } 58 59 blocking = false 60 61 keys := make([]interface{}, len(tasks)) 62 for i := range tasks { 63 keys[i] = tasks[i].in 64 } 65 66 out := m.F(keys) 67 for i, t := range tasks { 68 t.out <- out[i] 69 } 70 tasks = tasks[:0] 71 } 72 }() 73 } 74 } 75 76 func (m *Manager) Do(in interface{}) (interface{}, error) { 77 task := &task{ 78 in: in, 79 out: make(chan interface{}, 1), 80 } 81 m.batch <- task 82 v := <-task.out 83 if e, ok := v.(error); ok { 84 return nil, e 85 } 86 return v, nil 87 }