golang实现无锁队列
locklessqueue.go
//locklessqueue.go
package lockless
import (
"sync/atomic"
)
type LockFreeQueue struct {
buf []interface{}
len int32
head int32
tail int32
}
func NewQueue(n int32) *LockFreeQueue {
q := &LockFreeQueue{buf: make([]interface{}, n+1, n+1), len: n + 1}
return q
}
func (s *LockFreeQueue) PushBack(v interface{}) {
for {
tail := atomic.LoadInt32(&s.tail)
n := (tail + 1) % s.len
if atomic.CompareAndSwapInt32(&s.head, n, n) {
continue // 队列满了
}
if !atomic.CompareAndSwapInt32(&s.tail, tail, n) {
continue // 获取失败
}
s.buf[tail] = v
break
}
}
func (s *LockFreeQueue) PopFront() interface{} {
for {
tail := atomic.LoadInt32(&s.tail)
head := atomic.LoadInt32(&s.head)
if tail == head {
continue
}
n := (head + 1) % s.len
if !atomic.CompareAndSwapInt32(&s.head, head, n) {
continue
}
return s.buf[head]
}
}
测试代码
locklessqueue_test.go
//locklessqueue_test.go
package lockless
import (
"sync"
"testing"
)
func TestName(t *testing.T) {
lq := NewQueue(10)
w := sync.WaitGroup{}
for i := 0; i < 100; i++ {
w.Add(1)
go func(gi int) {
lq.PushBack(gi)
w.Done()
}(i)
}
go func() {
for {
lq.PopFront()
// time.Sleep(1 * time.Second)
}
}()
w.Wait()
}
var ch = make(chan interface{}, 50000)
func BenchmarkGo_Chan(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
ch <- 123
go func() {
<-ch
}()
}
}
func BenchmarkGo_LockFree(b *testing.B) {
lq := NewQueue(1000000000)
b.ResetTimer()
for i := 0; i < b.N; i++ {
lq.PushBack(123)
go func() {
lq.PopFront()
}()
}
}
执行命令
PS D:\golang\src\Test\Test> go test -v locklessqueue_test.go locklessqueue.go
=== RUN TestName
--- PASS: TestName (0.00s)
PASS
ok command-line-arguments 0.173s
性能测试
D:\golang\src\Test\Test> go test -v -bench="." locklessqueue_test.go locklessqueue.go
=== RUN TestName
--- PASS: TestName (0.00s)
goos: windows
goarch: amd64
cpu: Intel(R) Core(TM) i5-9500F CPU @ 3.00GHz
BenchmarkGo_Chan
BenchmarkGo_Chan-6 2957491 414.7 ns/op
BenchmarkGo_LockFree
BenchmarkGo_LockFree-6 4356723 272.4 ns/op
PASS
ok command-line-arguments 85.410s