github.com/bruceshao/lockfree@v1.1.3-0.20230816090528-e89824c0a6e9/producer_test.go (about) 1 /* 2 * Copyright (C) THL A29 Limited, a Tencent company. All rights reserved. 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 * 6 */ 7 8 package lockfree 9 10 import ( 11 "fmt" 12 "math/rand" 13 "os" 14 "reflect" 15 "sync" 16 "sync/atomic" 17 "testing" 18 "time" 19 "unsafe" 20 ) 21 22 const ( 23 GoSize = 5000 24 SchPerGo = 10000 25 ) 26 27 type longEventHandler[T uint64] struct { 28 count int32 29 ts time.Time 30 } 31 32 func (h *longEventHandler[T]) OnEvent(v uint64) { 33 atomic.AddInt32(&h.count, 1) 34 if h.count == 1 { 35 h.ts = time.Now() 36 } 37 fmt.Println("consumer ", v) 38 //if v%1000000 == 0 { 39 // fmt.Printf("read %d\n", v) 40 //} 41 if h.count == GoSize*SchPerGo { 42 tl := time.Since(h.ts) 43 fmt.Printf("read time = %d ms\n", tl.Milliseconds()) 44 } 45 } 46 47 func TestAA(t *testing.T) { 48 var ( 49 t1_10us = uint64(0) // 1-10微秒 50 t10_100us = uint64(0) // 10-100微秒 51 t100_1000us = uint64(0) // 100-1000微秒 52 t1_10ms = uint64(0) // 1-10毫秒 53 t10_100ms = uint64(0) // 10-100毫秒 54 t100_ms = uint64(0) // 大于100毫秒 55 slower = uint64(0) 56 counter = uint64(0) 57 ) 58 eh := &longEventHandler[uint64]{} 59 //queue, err := NewProducer[uint64](1024*1024, 1, eh, &SleepWaitStrategy{ 60 // t: time.Nanosecond * 1, 61 //}) 62 disruptor := NewLockfree[uint64](1024*1024*128, eh, 63 NewSleepBlockStrategy(time.Microsecond)) 64 disruptor.Start() 65 producer := disruptor.Producer() 66 var wg sync.WaitGroup 67 wg.Add(GoSize) 68 totalS := time.Now() 69 for i := 0; i < GoSize; i++ { 70 go func() { 71 for j := 0; j < SchPerGo; j++ { 72 x := atomic.AddUint64(&counter, 1) 73 ts := time.Now() 74 err := producer.Write(x) 75 if err != nil { 76 panic(err) 77 } 78 tl := time.Since(ts) 79 ms := tl.Microseconds() 80 if ms > 1 { 81 atomic.AddUint64(&slower, 1) 82 if ms < 10 { // t1_10us 83 atomic.AddUint64(&t1_10us, 1) 84 } else if ms < 100 { 85 atomic.AddUint64(&t10_100us, 1) 86 } else if ms < 1000 { 87 atomic.AddUint64(&t100_1000us, 1) 88 } else if ms < 10000 { 89 atomic.AddUint64(&t1_10ms, 1) 90 } else if ms < 100000 { 91 atomic.AddUint64(&t10_100ms, 1) 92 } else { 93 atomic.AddUint64(&t100_ms, 1) 94 } 95 } 96 } 97 wg.Done() 98 }() 99 } 100 wg.Wait() 101 totalL := time.Since(totalS) 102 fmt.Printf("write total time = [%d ms]\n", totalL.Milliseconds()) 103 fmt.Println("----- write complete -----") 104 time.Sleep(time.Second * 3) 105 disruptor.Close() 106 fmt.Printf("slow ratio = %.2f \n", float64(slower)*100.0/float64(counter)) 107 fmt.Printf("quick ratio = %.2f \n", float64(counter-slower)*100.0/float64(counter)) 108 fmt.Printf("[<1us][%d] \n", counter-slower) 109 fmt.Printf("[1-10us][%d] \n", t1_10us) 110 fmt.Printf("[10-100us][%d] \n", t10_100us) 111 fmt.Printf("[100-1000us][%d] \n", t100_1000us) 112 fmt.Printf("[1-10ms][%d] \n", t1_10ms) 113 fmt.Printf("[10-100ms][%d] \n", t10_100ms) 114 fmt.Printf("[>100ms][%d] \n", t100_ms) 115 } 116 117 func TestB(t *testing.T) { 118 var x = uint64(100) 119 typeOf := reflect.TypeOf(x) 120 fmt.Println(typeOf) 121 fmt.Println(os.Getpagesize()) 122 } 123 124 func TestC(t *testing.T) { 125 x := 128 - unsafe.Sizeof(uint64(0))%128 126 fmt.Println(x) 127 } 128 129 func TestProducer_WriteWindow(t *testing.T) { 130 eh := &sleepEventHandler[uint64]{ 131 sm: time.Second, 132 } 133 disruptor := NewLockfree[uint64](1, eh, 134 NewSleepBlockStrategy(time.Microsecond)) 135 disruptor.Start() 136 producer := disruptor.Producer() 137 // 写入10个数:0-9 138 // 预期结果,0可以写入,写入后在1ms内被取走,此时0会在等待1s后被打印,但由于ringbuffer有空位,所以1可以被写入 139 // 1写入后一直无法被取走,因为在等待1s内0的打印,后续其他值均无法被写入,因为1导致ringbuffer满了 140 for i := 0; i < 10; i++ { 141 ww := producer.WriteWindow() 142 if ww <= 0 { 143 // 表示不能写入,丢弃 144 fmt.Println("discard ", i , " window ", ww) 145 } else { 146 // 实际写入 147 producer.Write(uint64(i)) 148 } 149 // 为了给予consumer时间取走 150 time.Sleep(time.Millisecond) 151 } 152 // 为了可以看到打印的结果 153 time.Sleep(3 * time.Second) 154 disruptor.Close() 155 } 156 157 func TestWriteTimeout(t *testing.T) { 158 var counter = uint64(0) 159 // 写入超时,如何使用 160 eh := &longSleepEventHandler[uint64]{} 161 disruptor := NewLockfree[uint64](2, eh, NewSleepBlockStrategy(time.Microsecond)) 162 disruptor.Start() 163 producer := disruptor.Producer() 164 // 假设有10个写g 165 var wg sync.WaitGroup 166 for i := 0; i < 100; i++ { 167 wg.Add(1) 168 go func() { 169 for j := 0; j < 100; j++ { 170 v := atomic.AddUint64(&counter, 1) 171 wc, exist, err := producer.WriteTimeout(v, time.Millisecond) 172 if err != nil { 173 return 174 } 175 if !exist { 176 // 重复写入1次,写入不成功则丢弃重新写其他的 177 if ok, _ := producer.WriteByCursor(v, wc); ok { 178 continue 179 } 180 fmt.Println("discard ", v) 181 // 重新生成值,一直等待写入 182 v = atomic.AddUint64(&counter, 1) 183 for { 184 if ok, _ := producer.WriteByCursor(v, wc); ok { 185 fmt.Println("write ", v, " with x times") 186 break 187 } 188 // 写入不成功则休眠,防止CPU暴增 189 time.Sleep(100 * time.Microsecond) 190 } 191 } else { 192 fmt.Println("write ", v, " with 1 time") 193 } 194 } 195 wg.Done() 196 }() 197 } 198 wg.Wait() 199 time.Sleep(3 * time.Second) 200 disruptor.Close() 201 } 202 203 204 // sleepEventHandler 休眠性质的事件处理器 205 type sleepEventHandler[T uint64] struct { 206 sm time.Duration 207 } 208 209 func (h *sleepEventHandler[T]) OnEvent(v uint64) { 210 time.Sleep(h.sm) 211 fmt.Println("consumer ", v) 212 } 213 214 type longSleepEventHandler[T uint64] struct { 215 count int32 216 } 217 218 func (h *longSleepEventHandler[T]) OnEvent(v uint64) { 219 // 每次处理都会进行随机休眠,可以导致消费端变慢 220 intn := rand.Intn(1000) 221 time.Sleep(time.Duration(intn * 1000)) 222 fmt.Println("consumer count ", atomic.AddInt32(&h.count, 1)) 223 }