github.com/15mga/kiwi@v0.0.2-0.20240324021231-b95d5c3ac751/worker/worker.go (about) 1 package worker 2 3 import ( 4 "fmt" 5 "github.com/15mga/kiwi" 6 "sync" 7 8 "github.com/15mga/kiwi/util" 9 ) 10 11 func NewWorker[T any](fn func(T)) *Worker[T] { 12 b := &Worker[T]{ 13 ch: make(chan struct{}, 1), 14 fn: fn, 15 pool: sync.Pool{ 16 New: func() any { 17 return &job[T]{} 18 }, 19 }, 20 } 21 return b 22 } 23 24 type Worker[T any] struct { 25 mtx sync.Mutex 26 ch chan struct{} 27 head *job[T] 28 tail *job[T] 29 curr *job[T] 30 fn func(T) 31 pool sync.Pool 32 } 33 34 func (w *Worker[T]) Start() { 35 go func() { 36 defer func() { 37 if err := recover(); err != nil { 38 //fmt.Printf("\033[31m!!!recover!!!\u001B[0m\n%s%s\n", err, util.GetStack(5)) 39 kiwi.Error2(util.EcServiceErr, util.M{ 40 "error": fmt.Sprint(err), 41 }) 42 w.Start() 43 } 44 }() 45 46 w.do() 47 48 for range w.ch { 49 for { 50 w.mtx.Lock() 51 w.curr = w.head 52 w.head = nil 53 w.tail = nil 54 w.mtx.Unlock() 55 56 if w.curr == nil { 57 break 58 } 59 w.do() 60 } 61 } 62 }() 63 } 64 65 func (w *Worker[T]) Dispose() { 66 close(w.ch) 67 } 68 69 func (w *Worker[T]) Push(item T) { 70 e := w.pool.Get().(*job[T]) 71 e.value = item 72 w.mtx.Lock() 73 if w.head != nil { 74 w.tail.next = e 75 } else { 76 w.head = e 77 } 78 w.tail = e 79 w.mtx.Unlock() 80 81 select { 82 case w.ch <- struct{}{}: 83 default: 84 } 85 } 86 87 func (w *Worker[T]) do() { 88 var ( 89 j *job[T] 90 val T 91 ) 92 for { 93 if w.curr == nil { 94 break 95 } 96 j = w.curr 97 val = j.value 98 w.curr = j.next 99 j.next = nil 100 w.pool.Put(j) 101 w.fn(val) 102 } 103 } 104 105 type job[T any] struct { 106 next *job[T] 107 value T 108 } 109 110 type FnJob func(*Job) 111 112 func NewJobWorker(fn FnJob) *JobWorker { 113 w := &JobWorker{ 114 pcr: fn, 115 } 116 w.Worker = NewWorker[*Job](w.process) 117 return w 118 } 119 120 type JobWorker struct { 121 *Worker[*Job] 122 pcr FnJob 123 } 124 125 func (w *JobWorker) process(j *Job) { 126 w.pcr(j) 127 j.Data = nil 128 _JobPool.Put(j) 129 } 130 131 func (w *JobWorker) Push(name JobName, data ...any) { 132 j := _JobPool.Get().(*Job) 133 j.Name = name 134 j.Data = data 135 w.Worker.Push(j) 136 } 137 138 type JobName = string 139 140 type Job struct { 141 Name JobName 142 Data []any 143 } 144 145 var ( 146 _JobPool = sync.Pool{ 147 New: func() any { 148 return &Job{} 149 }, 150 } 151 ) 152 153 func SpawnJob() *Job { 154 return _JobPool.Get().(*Job) 155 } 156 157 func RecycleJob(job *Job) { 158 _JobPool.Put(job) 159 } 160 161 type FnJobData struct { 162 Fn util.FnAnySlc 163 Params []any 164 } 165 166 type FnWorker struct { 167 *Worker[FnJobData] 168 } 169 170 func NewFnWorker() *FnWorker { 171 return &FnWorker{ 172 Worker: NewWorker[FnJobData](func(data FnJobData) { 173 data.Fn(data.Params) 174 }), 175 } 176 } 177 178 func (w *FnWorker) Push(fn util.FnAnySlc, params ...any) { 179 w.Worker.Push(FnJobData{ 180 Fn: fn, 181 Params: params, 182 }) 183 }