github.com/vanus-labs/vanus/lib@v0.0.0-20231221070800-1334a7b9605e/executor/multi_flow.go (about) 1 // Copyright 2023 Linkall Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package executor 16 17 import ( 18 // standard libraries. 19 "sync/atomic" 20 21 // this project. 22 "github.com/vanus-labs/vanus/lib/container/conque/blocking" 23 "github.com/vanus-labs/vanus/lib/container/conque/unbounded" 24 ) 25 26 const defaultInvokeBatchSize = 8 27 28 type flow struct { 29 q unbounded.Queue[Task] 30 state int32 31 mf *MultiFlow 32 } 33 34 // Make sure flow implements ExecuteCloser. 35 var _ ExecuteCloser = (*flow)(nil) 36 37 func (f *flow) Execute(t Task) bool { 38 if atomic.LoadInt32(&f.state) != 0 { 39 return false 40 } 41 42 if f.q.Push(t) { 43 return f.mf.q.Push(f) 44 } 45 return true 46 } 47 48 func (f *flow) Close() { 49 atomic.StoreInt32(&f.state, 1) 50 } 51 52 func (f *flow) invokeTasks(batch int) bool { 53 if atomic.LoadInt32(&f.state) != 0 { 54 return false 55 } 56 57 for i := 0; i < batch; i++ { 58 t, _ := f.q.Peek() 59 60 t() 61 62 _, empty, _ := f.q.UniquePop() 63 if empty { 64 return false 65 } 66 } 67 return true 68 } 69 70 type MultiFlow struct { 71 q blocking.Queue[*flow] 72 parallel int 73 } 74 75 func NewMultiFlow(parallel int, handoff, startImmediately bool) *MultiFlow { 76 return new(MultiFlow).Init(parallel, handoff, startImmediately) 77 } 78 79 func (mf *MultiFlow) Init(parallel int, handoff, startImmediately bool) *MultiFlow { 80 mf.parallel = parallel 81 mf.q.Init(handoff) 82 if startImmediately { 83 mf.Start() 84 } 85 return mf 86 } 87 88 func (mf *MultiFlow) Start() { 89 for i := 0; i < mf.parallel; i++ { 90 go mf.run() 91 } 92 } 93 94 func (mf *MultiFlow) Close() { 95 mf.q.Close() 96 } 97 98 func (mf *MultiFlow) NewFlow() ExecuteCloser { 99 f := &flow{ 100 mf: mf, 101 } 102 return f 103 } 104 105 func (mf *MultiFlow) run() { 106 for { 107 f, ok := mf.q.SharedPop() 108 if !ok { 109 return 110 } 111 112 if f.invokeTasks(defaultInvokeBatchSize) { 113 mf.q.Push(f) 114 } 115 } 116 }