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  }