sync.Mutex
dần trở nên không hiệu quả, khiến hiệu suất và độ trễ đột ngột tăng cao. Đây chính là lúc lock-free data structures – các cấu trúc dữ liệu không khóa – xuất hiện như một vị cứu tinh, sử dụng các thao tác nguyên tử để loại bỏ hoàn toàn tình trạng chờ đợi.mutex
). Thay vào đó, nó sử dụng các phép toán nguyên tử (atomic operations) như Compare-And-Swap (CAS)
để đồng bộ.Tiêu chí | Lock-Based (Mutex) | Lock-Free |
---|---|---|
Tính an toàn | Có | Có |
Khả năng chờ đợi | Rất cao (block/goroutine) | Không hoặc rất ít |
Hiệu năng | Giảm khi contention cao | Tốt hơn khi đa luồng nhiều |
Rủi ro deadlock | Có | Loại bỏ deadlock hoàn toàn |
sync/atomic
để thao tác với các giá trị nguyên tử.atomic.CompareAndSwapInt32
: So sánh và thay thế giá trị nếu đúngatomic.AddInt64
: Cộng hoặc trừ an toànatomic.LoadInt32
/ atomic.StoreInt32
: Đọc/ghi mà không bị race conditionatomic.AddInt64
tăng giá trị biến counter
một cách nguyên tử.sync.Mutex
khi số luồng lớn.package main
import ( "fmt" "sync" "sync/atomic" "unsafe")
type Node struct { value int next *Node}
type LockFreeQueue struct { head *Node tail *Node}
func NewLockFreeQueue() *LockFreeQueue { dummy := &Node{} return &LockFreeQueue{head: dummy, tail: dummy}}
func (q *LockFreeQueue) Enqueue(value int) { newNode := &Node{value: value} for { tail := q.tail next := tail.next if tail == q.tail { if next == nil { if atomic.CompareAndSwapPointer( (*unsafe.Pointer)(unsafe.Pointer(&tail.next)), unsafe.Pointer(next), unsafe.Pointer(newNode), ) { atomic.CompareAndSwapPointer( (*unsafe.Pointer)(unsafe.Pointer(&q.tail)), unsafe.Pointer(tail), unsafe.Pointer(newNode), ) return } } else { atomic.CompareAndSwapPointer( (*unsafe.Pointer)(unsafe.Pointer(&q.tail)), unsafe.Pointer(tail), unsafe.Pointer(next), ) } } }}
func main() { q := NewLockFreeQueue() var wg sync.WaitGroup
for i := 0; i < 10; i++ { wg.Add(1) go func(v int) { defer wg.Done() q.Enqueue(v) }(i) } wg.Wait() fmt.Println("Queue loaded!")}
CompareAndSwapPointer
để cập nhật con trỏ next và tail mà không khóa.package main
import ( "fmt" "sync" "sync/atomic")
type Shard struct { value atomic.Value // chứa map[int]int}
type LockFreeMap struct { shards []*Shard}
func NewLockFreeMap(size int) *LockFreeMap { m := &LockFreeMap{shards: make([]*Shard, size)} for i := range m.shards { m.shards[i] = &Shard{} m.shards[i].value.Store(make(map[int]int)) } return m}
func (m *LockFreeMap) Set(key, value int) { shard := m.shards[key%len(m.shards)] for { oldMap := shard.value.Load().(map[int]int) newMap := make(map[int]int) for k, v := range oldMap { newMap[k] = v } newMap[key] = value if shard.value.CompareAndSwap(oldMap, newMap) { break } }}
func main() { m := NewLockFreeMap(4) var wg sync.WaitGroup
for i := 0; i < 100; i++ { wg.Add(1) go func(k int) { defer wg.Done() m.Set(k, k*2) }(i) } wg.Wait() fmt.Println("Map ready!")}
atomic.Value
và CAS để thay thế toàn bộ shard theo kiểu nguyên tử.Cạm bẫy | Mô Tả | Giải Pháp |
---|---|---|
CAS Overload | Retry CAS nhiều, giảm hiệu năng | Phân shard dữ liệu hoặc dùng locking |
ABA Problem | Con trỏ thay đổi kiểu A->B->A gây nhầm lẫn | Thêm version tag kiểm soát |
Deadlock (không còn) | Đồng bộ lock-based bị kẹt | Lock-free đã loại bỏ |
sync.Mutex
gây tắc nghẽn, độ trễ lên tới 10ms.Chỉ số | Trước (Mutex) | Sau (Lock-Free) |
---|---|---|
Độ trễ (Latency) | 5ms | 2ms (-60%) |
Throughput | 80k tasks/s | 120k tasks/s (+50%) |
CPU Usage | Bình thường | Tăng nhẹ do retries |
sync/atomic
trong Go hỗ trợ xây dựng counter, queue, map lock-free.