GO实现无锁队列 在使用Go进行多线程开发时,通常通过给队列加锁的方式避免并发读写带来的数据丢失或重复读取等问题,但在高并发条件下,加锁带来的性能降低也是必然的,因此希望通过实现lock-free queue 的算法实现无锁队列,提高程序性能。

通过lock-free queue ,实现无锁队列,进而提升Go程序性能。

随着并发数越高,无锁队列的执行效率越高。

详细方案:

引用atomic包,实现lock-free queue 算法(Compare and swap),实现无锁队列:

package queue
import (
	"sync/atomic"
	"unsafe"
)

// 定义无锁队列结构
type LKQueue struct {
	head unsafe.Pointer
	tail unsafe.Pointer
}

type node struct {
	value interface{}
	next  unsafe.Pointer
}

// 新建队列,返回一个空队列
func NewLKQueue() *LKQueue {
	n := unsafe.Pointer(&node{})
	return &LKQueue{head: n, tail: n}
}

// 插入,将给定的值v放在队列的尾部
func (q *LKQueue) Enqueue(v interface{}) {
	n := &node{value: v}
	for {
		tail := load(&q.tail)
		next := load(&tail.next)
		if tail == load(&q.tail) {
			if next == nil {
				if cas(&tail.next, next, n) {
					cas(&q.tail, tail, n) // 排队完成, 尝试将tail移到插入的节点
					return
				}
			} else { // tail没有指向最后一个节点
				// 将Tail移到下一个节点
				cas(&q.tail, tail, next)
			}
		}
	}
}

// 移除,删除并返回队列头部的值,如果队列为空,则返回nil
func (q *LKQueue) Dequeue() interface{} {
	for {
		head := load(&q.head)
		tail := load(&q.tail)
		next := load(&head.next)
		if head == load(&q.head) { 
			if head == tail { 
				if next == nil { 
					return nil
				}
				
				cas(&q.tail, tail, next)
			} else {
				// 在CAS之前读取值,否则另一个出队列可能释放下一个节点
				v := next.value
				if cas(&q.head, head, next) {
					return v
				}
			}
		}
	}
}

func load(p *unsafe.Pointer) (n *node) {
	return (*node)(atomic.LoadPointer(p))
}

// CAS算法
func cas(p *unsafe.Pointer, old, new *node) (ok bool) {
	return atomic.CompareAndSwapPointer(
		p, unsafe.Pointer(old), unsafe.Pointer(new))
}
GO实现无锁队列
在使用Go进行多线程开发时,通常通过给队列加锁的方式避免并发读写带来的数据丢失或重复读取等问题,但在高并发条件下,加锁带来的性能降低也是必然的,因此希望通过实现lock-free queue 的算法实现无锁队列,提高程序性能。GO实现无锁队列
在使用Go进行多线程开发时,通常通过给队列加锁的方式避免并发读写带来的数据丢失或重复读取等问题,但在高并发条件下,加锁带来的性能降低也是必然的,因此希望通过实现lock-free queue 的算法实现无锁队列,提高程序性能。 

理解CAS算法的含义,大致为:

当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,
而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。