2024-11-12 08:10:09 +00:00
|
|
|
package ds_utils
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
|
2024-11-12 08:59:34 +00:00
|
|
|
common "git.mic.pp.ua/anderson/nettools/common"
|
2024-11-12 08:10:09 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// RunWorkerPool is a single function worker pool implementation
|
|
|
|
//
|
|
|
|
// Create a channel where u will send tasks, send some tasks
|
|
|
|
// there and they will execute.
|
|
|
|
// If there are too many tasks -- they will be saved to the queue.
|
|
|
|
//
|
|
|
|
// Also this function may be extended to have resizable capacity,
|
|
|
|
// more callbacks, tasks priority, but those modifications would
|
|
|
|
// harm performance.
|
|
|
|
//
|
|
|
|
// If you need out-of-the-box more flexible approach -- use WorkerPool struct instead.
|
|
|
|
// Also this wp is worse in terms of performance. IDK why it exists, it's just sucks.
|
|
|
|
func RunWorkerPool(
|
|
|
|
ctx context.Context,
|
|
|
|
tasksChan chan common.Task,
|
|
|
|
capacity int,
|
|
|
|
errHanlder func(error) error,
|
|
|
|
) (err error) {
|
|
|
|
countBusy := 0
|
|
|
|
errChan := make(chan error, 3)
|
|
|
|
tasksQueue := []common.Task{}
|
|
|
|
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case task := <-tasksChan:
|
|
|
|
if countBusy >= capacity {
|
|
|
|
tasksQueue = append(tasksQueue, task)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
go func() { errChan <- task(context.Background()) }()
|
|
|
|
countBusy++
|
|
|
|
|
|
|
|
case err := <-errChan:
|
|
|
|
if err != nil {
|
|
|
|
if err = errHanlder(err); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(tasksQueue) == 0 {
|
|
|
|
countBusy--
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
task := tasksQueue[0]
|
|
|
|
tasksQueue = tasksQueue[1:]
|
|
|
|
go func() { errChan <- task(context.Background()) }()
|
|
|
|
case <-ctx.Done():
|
|
|
|
return ctx.Err()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|