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

理解CAS算法的含義,大致為:

當多個線程嘗試使用CAS同時更新同一個變量時,只有其中一個線程能更新變量的值,
而其它線程都失敗,失敗的線程並不會被掛起,而是被告知這次競爭中失敗,並可以再次嘗試。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM