Skip to content

Instantly share code, notes, and snippets.

@omar391
Created May 6, 2026 16:29
Show Gist options
  • Select an option

  • Save omar391/9882eca078a59936582437727b691e4b to your computer and use it in GitHub Desktop.

Select an option

Save omar391/9882eca078a59936582437727b691e4b to your computer and use it in GitHub Desktop.
Go Channel vs Ring Buffer Benchmark
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