• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

GO实现无锁队列

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

通过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))
}
 

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

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

 


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
go语言中的运算符^,&发布时间:2022-07-10
下一篇:
go语言学习--channel的关闭发布时间:2022-07-10
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap