github.com/andy2046/gopie@v0.7.0/pkg/multilane/multilane.go (about) 1 // Package multilane implements a concurrent blocking multiset. 2 package multilane 3 4 import ( 5 "github.com/andy2046/gopie/pkg/spsc" 6 "runtime" 7 ) 8 9 const ( 10 defaultQSize uint32 = 1024 11 defaultWidth uint32 = 8 12 ) 13 14 var defaultQueFunc = func(size uint32) Queue { 15 return spsc.New(size) 16 } 17 18 type ( 19 // Queue represents the queue with Get / Put / Close methods. 20 Queue interface { 21 Get(interface{}) bool 22 Put(interface{}) 23 Close() 24 } 25 26 // Config for MultiLane. 27 Config struct { 28 LaneWidth uint32 // number of queue for MultiLane 29 QueueSize uint32 // size of each queue in MultiLane 30 New func(uint32) Queue 31 } 32 33 // MultiLane represents the concurrent multiset. 34 MultiLane struct { 35 _ [spsc.CacheLinePadSize]byte 36 lanes []Queue 37 laneMask int64 38 putCh chan int64 39 getCh chan int64 40 queSize uint32 41 _ [4]byte 42 } 43 ) 44 45 // New create a new MultiLane. 46 func New(conf Config) *MultiLane { 47 m := MultiLane{} 48 qs, w, queFunc := defaultQSize, defaultWidth, defaultQueFunc 49 if conf.New != nil { 50 queFunc = conf.New 51 } 52 if conf.QueueSize > 7 { 53 qs = conf.QueueSize 54 } 55 if conf.LaneWidth > 0 { 56 w = conf.LaneWidth 57 } 58 m.queSize = nextPowerOf2(qs) 59 m.lanes = make([]Queue, nextPowerOf2(w)) 60 m.laneMask = int64(len(m.lanes) - 1) 61 m.putCh = make(chan int64, len(m.lanes)) 62 m.getCh = make(chan int64, len(m.lanes)) 63 for i := range m.lanes { 64 m.lanes[i] = queFunc(m.queSize) 65 m.putCh <- int64(i) 66 m.getCh <- int64(i) 67 } 68 return &m 69 } 70 71 // GetLane get the value at the provided lane to given variable, 72 // blocking. 73 func (m *MultiLane) GetLane(lane uint32, i interface{}) bool { 74 return m.lanes[int64(lane)&m.laneMask].Get(i) 75 } 76 77 // PutLane put given variable at the provided lane, 78 // blocking. 79 func (m *MultiLane) PutLane(lane uint32, i interface{}) { 80 m.lanes[int64(lane)&m.laneMask].Put(i) 81 } 82 83 // Get the value at one of the lanes pointed by the cursor to given variable, 84 // blocking. 85 func (m *MultiLane) Get(i interface{}) bool { 86 for { 87 select { 88 case curs := <-m.getCh: 89 r := m.lanes[curs&m.laneMask].Get(i) 90 m.getCh <- curs 91 return r 92 default: 93 runtime.Gosched() 94 } 95 } 96 } 97 98 // Put given variable at one of the lanes pointed by the cursor, 99 // blocking. 100 func (m *MultiLane) Put(i interface{}) { 101 for { 102 select { 103 case curs := <-m.putCh: 104 m.lanes[curs&m.laneMask].Put(i) 105 m.putCh <- curs 106 return 107 default: 108 runtime.Gosched() 109 } 110 } 111 } 112 113 // Close the MultiLane, it shall NOT be called before `Put()`. 114 func (m *MultiLane) Close() { 115 for _, l := range m.lanes { 116 l.Close() 117 } 118 } 119 120 // LaneWidth is the number of lanes. 121 func (m *MultiLane) LaneWidth() uint32 { 122 return uint32(m.laneMask + 1) 123 } 124 125 // QueueSize is the size of the underlying queue. 126 func (m *MultiLane) QueueSize() uint32 { 127 return m.queSize 128 } 129 130 func nextPowerOf2(v uint32) uint32 { 131 v-- 132 v |= v >> 1 133 v |= v >> 2 134 v |= v >> 4 135 v |= v >> 8 136 v |= v >> 16 137 return v + 1 138 }