github.com/asynkron/protoactor-go@v0.0.0-20240308120642-ef91a6abee75/internal/queue/mpsc/mpsc_test.go (about) 1 package mpsc 2 3 import ( 4 "fmt" 5 "runtime" 6 "sync" 7 "testing" 8 9 "github.com/stretchr/testify/assert" 10 ) 11 12 func TestQueue_PushPop(t *testing.T) { 13 q := New() 14 15 q.Push(1) 16 q.Push(2) 17 assert.Equal(t, 1, q.Pop()) 18 assert.Equal(t, 2, q.Pop()) 19 assert.True(t, q.Empty()) 20 } 21 22 func TestQueue_Empty(t *testing.T) { 23 q := New() 24 assert.True(t, q.Empty()) 25 q.Push(1) 26 assert.False(t, q.Empty()) 27 } 28 29 func TestQueue_PushPopOneProducer(t *testing.T) { 30 expCount := 100 31 32 var wg sync.WaitGroup 33 wg.Add(1) 34 q := New() 35 go func() { 36 i := 0 37 for { 38 r := q.Pop() 39 if r == nil { 40 runtime.Gosched() 41 continue 42 } 43 i++ 44 if i == expCount { 45 wg.Done() 46 return 47 } 48 } 49 }() 50 51 var val interface{} = "foo" 52 53 for i := 0; i < expCount; i++ { 54 q.Push(val) 55 } 56 57 wg.Wait() 58 } 59 60 //func TestMpscQueueConsistency(t *testing.T) { 61 // max := 1000000 62 // c := runtime.NumCPU() / 2 63 // cmax := max / c 64 // var wg sync.WaitGroup 65 // wg.Add(1) 66 // q := New() 67 // 68 // go func() { 69 // i := 0 70 // seen := make(map[string]string) 71 // for { 72 // r := q.Pop() 73 // if r == nil { 74 // runtime.Gosched() 75 // 76 // continue 77 // } 78 // i++ 79 // s, _ := r.(string) 80 // _, present := seen[s] 81 // if present { 82 // log.Printf("item have already been seen %v", s) 83 // t.FailNow() 84 // } 85 // seen[s] = s 86 // if i == cmax*c { 87 // wg.Done() 88 // return 89 // } 90 // } 91 // }() 92 // 93 // for j := 0; j < c; j++ { 94 // jj := j 95 // go func() { 96 // for i := 0; i < cmax; i++ { 97 // if rand.Intn(10) == 0 { 98 // time.Sleep(time.Duration(rand.Intn(1000))) 99 // } 100 // q.Push(fmt.Sprintf("%v %v", jj, i)) 101 // } 102 // }() 103 // } 104 // 105 // wg.Wait() 106 // time.Sleep(500 * time.Millisecond) 107 // // queue should be empty 108 // for i := 0; i < 100; i++ { 109 // r := q.Pop() 110 // if r != nil { 111 // log.Printf("unexpected result %+v", r) 112 // t.FailNow() 113 // } 114 // } 115 //} 116 117 func benchmarkPushPop(count, c int) { 118 var wg sync.WaitGroup 119 wg.Add(1) 120 q := New() 121 go func() { 122 i := 0 123 for { 124 r := q.Pop() 125 if r == nil { 126 runtime.Gosched() 127 continue 128 } 129 i++ 130 if i == count { 131 wg.Done() 132 return 133 } 134 } 135 }() 136 137 var val interface{} = "foo" 138 139 for i := 0; i < c; i++ { 140 go func(n int) { 141 for n > 0 { 142 q.Push(val) 143 n-- 144 } 145 }(count / c) 146 } 147 148 wg.Wait() 149 } 150 151 func benchmarkChannelPushPop(count, c int) { 152 var wg sync.WaitGroup 153 wg.Add(1) 154 ch := make(chan interface{}, 100) 155 go func() { 156 i := 0 157 for { 158 <-ch 159 i++ 160 if i == count { 161 wg.Done() 162 return 163 } 164 } 165 }() 166 167 var val interface{} = "foo" 168 169 for i := 0; i < c; i++ { 170 go func(n int) { 171 for n > 0 { 172 ch <- val 173 n-- 174 } 175 }(count / c) 176 } 177 } 178 179 func BenchmarkPushPop(b *testing.B) { 180 benchmarks := []struct { 181 count int 182 concurrency int 183 }{ 184 { 185 count: 10000, 186 concurrency: 1, 187 }, 188 { 189 count: 10000, 190 concurrency: 2, 191 }, 192 { 193 count: 10000, 194 concurrency: 4, 195 }, 196 { 197 count: 10000, 198 concurrency: 8, 199 }, 200 } 201 for _, bm := range benchmarks { 202 b.Run(fmt.Sprintf("%d_%d", bm.count, bm.concurrency), func(b *testing.B) { 203 for i := 0; i < b.N; i++ { 204 benchmarkPushPop(bm.count, bm.concurrency) 205 } 206 }) 207 } 208 } 209 210 func BenchmarkChannelPushPop(b *testing.B) { 211 benchmarks := []struct { 212 count int 213 concurrency int 214 }{ 215 { 216 count: 10000, 217 concurrency: 1, 218 }, 219 { 220 count: 10000, 221 concurrency: 2, 222 }, 223 { 224 count: 10000, 225 concurrency: 4, 226 }, 227 { 228 count: 10000, 229 concurrency: 8, 230 }, 231 } 232 for _, bm := range benchmarks { 233 b.Run(fmt.Sprintf("%d_%d", bm.count, bm.concurrency), func(b *testing.B) { 234 for i := 0; i < b.N; i++ { 235 benchmarkChannelPushPop(bm.count, bm.concurrency) 236 } 237 }) 238 } 239 }