Created
May 6, 2026 16:29
-
-
Save omar391/9882eca078a59936582437727b691e4b to your computer and use it in GitHub Desktop.
Go Channel vs Ring Buffer Benchmark
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package bench | |
| import ( | |
| "sync" | |
| "sync/atomic" | |
| "testing" | |
| ) | |
| type RingBuffer struct { | |
| head uint64 | |
| _ [56]byte // Padding | |
| tail uint64 | |
| _ [56]byte // Padding | |
| mask uint64 | |
| data []interface{} | |
| } | |
| func NewRingBuffer(size uint64) *RingBuffer { | |
| return &RingBuffer{ | |
| mask: size - 1, | |
| data: make([]interface{}, size), | |
| } | |
| } | |
| func (rb *RingBuffer) Push(item interface{}) bool { | |
| // Simple MPSC push via CAS | |
| for { | |
| tail := atomic.LoadUint64(&rb.tail) | |
| head := atomic.LoadUint64(&rb.head) | |
| if tail-head >= rb.mask+1 { | |
| return false | |
| } | |
| if atomic.CompareAndSwapUint64(&rb.tail, tail, tail+1) { | |
| rb.data[tail&rb.mask] = item | |
| return true | |
| } | |
| } | |
| } | |
| func (rb *RingBuffer) Pop() (interface{}, bool) { | |
| head := atomic.LoadUint64(&rb.head) | |
| tail := atomic.LoadUint64(&rb.tail) | |
| if head == tail { | |
| return nil, false | |
| } | |
| item := rb.data[head&rb.mask] | |
| atomic.StoreUint64(&rb.head, head+1) | |
| return item, true | |
| } | |
| func BenchmarkChannel_MPMC(b *testing.B) { | |
| ch := make(chan int, 1024) | |
| b.ResetTimer() | |
| var wg sync.WaitGroup | |
| // 10 producers | |
| for p := 0; p < 10; p++ { | |
| wg.Add(1) | |
| go func() { | |
| defer wg.Done() | |
| for i := 0; i < b.N/10; i++ { | |
| ch <- i | |
| } | |
| }() | |
| } | |
| // 1 consumer | |
| go func() { | |
| for i := 0; i < (b.N/10)*10; i++ { | |
| <-ch | |
| } | |
| }() | |
| wg.Wait() | |
| } | |
| func BenchmarkRingBuffer_MPMC(b *testing.B) { | |
| rb := NewRingBuffer(1024) | |
| b.ResetTimer() | |
| var wg sync.WaitGroup | |
| for p := 0; p < 10; p++ { | |
| wg.Add(1) | |
| go func() { | |
| defer wg.Done() | |
| for i := 0; i < b.N/10; i++ { | |
| for !rb.Push(i) { | |
| } | |
| } | |
| }() | |
| } | |
| go func() { | |
| for i := 0; i < (b.N/10)*10; i++ { | |
| for { | |
| if _, ok := rb.Pop(); ok { | |
| break | |
| } | |
| } | |
| } | |
| }() | |
| wg.Wait() | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment