学习笔记 | Go 高性能 - 无锁编程

简介: 学习笔记 | Go 高性能 - 无锁编程

go01.jpeg

  • 锁是一种常见的同步机制,用来解决多个线程同时访问共享资源导致的数据竞争问题。在高并发场景下,锁的使用可能会成为性能瓶颈,因为线程需要频繁地加锁和释放锁,这会增加上下文切换开销并降低程序的吞吐量。
  • 无锁编程(lock-free programming)是一种并发编程技术,主要用于消除多线程编程中锁操作带来的性能损耗。


lock-free的优势

  • 减少线程阻塞和等待时间
  • 避免线程的优先级反转
  • 提高并发性能
  • 消除竞态条件(race condition)、死锁、饿死等潜在问题
  • 代码更加清晰易懂


CAS (compare and swap) 是原子操作的一种,用于在多线程中实现原子数据交换,避免多线程同时改写某一共享数据时,由于执行顺序不确定性以及中断的不可预知性产生的数据不一致问题。


示例: 栈操作

// Stack 接口

type StackInterface interface{

Push(interface{})

Pop()interface{}

}


  • 有锁: 使用 sync 包

// 互斥锁实现的栈 (有锁编程)

type MutexStack struct{

// 栈元素容器用切片表示

v []interface{}

// 互斥锁

mu sync.Mutex

}


funcNewMutexStack()*MutexStack {

return&MutexStack{v:make([]interface{},0)}

}


func(s *MutexStack)Push(v interface{}){

// 可能同时有多个 goroutine 操作

// 栈元素操作为临界区,需要加锁

s.mu.Lock()

s.v =append(s.v, v)

s.mu.Unlock()

}


func(s *MutexStack)Pop()interface{}{

// 可能同时有多个 goroutine 操作

// 栈元素操作为临界区,需要加锁

s.mu.Lock()

var v interface{}

iflen(s.v)>0{

 v = s.v[len(s.v)-1]

 s.v = s.v[:len(s.v)-1]

}

s.mu.Unlock()

return v

}


  • 无锁: atomic 包

// 栈元素节点

type directItem struct{

next unsafe.Pointer

v    interface{}

}


// CAS 操作实现的栈 (无锁编程)

type LockFreeStack struct{

// 栈元素容器用链表表示

top unsafe.Pointer

// 栈长度

lenuint64

}


funcNewLockFreeStack()*LockFreeStack {

return&LockFreeStack{}

}


func(s *LockFreeStack)Push(v interface{}){

item := directItem{v: v}

var top unsafe.Pointer


for{

 top = atomic.LoadPointer(&s.top)

 item.next = top

 if atomic.CompareAndSwapPointer(&s.top, top, unsafe.Pointer(&item)){

  // 只有 1 个 goroutine 可以执行到这里

  // 栈元素数量 + 1

  atomic.AddUint64(&s.len,1)

  return

 }

}

}


func(s *LockFreeStack)Pop()interface{}{

var top, next unsafe.Pointer

var item *directItem


for{

 top = atomic.LoadPointer(&s.top)

 if top ==nil{

  returnnil

 }

 item =(*directItem)(top)

 next = atomic.LoadPointer(&item.next)

 if atomic.CompareAndSwapPointer(&s.top, top, next){

  // 只有 1 个 goroutine 可以执行到这里

  // 栈元素数量 - 1

  atomic.AddUint64(&s.len,^uint64(0))

  return item.v

 }

}

}


测试结果比较

$ go test -run='^$' -bench=. -count=1 -benchtime=2s


## 输出结果如下

Benchmark_Stack/*performance.LockFreeStack-8            16553013               134.0 ns/op

Benchmark_Stack/*performance.MutexStack-8               20625786               172.5 ns/op

目录
相关文章
|
6月前
|
负载均衡 Java 中间件
使用Go语言构建高性能Web服务
Go语言作为一种快速、高效的编程语言,其在构建高性能Web服务方面具有独特优势。本文将探讨如何利用Go语言开发和优化Web服务,以实现更高的性能和可伸缩性。
|
6月前
|
监控 安全 Java
Go语言学习笔记(一)
Go语言学习笔记(一)
123 1
|
6月前
|
存储 缓存 安全
Go 简单设计和实现可扩展、高性能的泛型本地缓存
本文将会探讨如何极简设计并实现一个可扩展、高性能的本地缓存。支持多样化的缓存策略,例如 最近最少使用(LRU)等。
102 0
Go 简单设计和实现可扩展、高性能的泛型本地缓存
|
9天前
|
安全 Go 调度
Go语言中的并发编程:解锁高性能程序设计之门####
探索Go语言如何以简洁高效的并发模型,重新定义现代软件开发的边界。本文将深入剖析Goroutines与Channels的工作原理,揭秘它们为何成为实现高并发、高性能应用的关键。跟随我们的旅程,从基础概念到实战技巧,一步步揭开Go并发编程的神秘面纱,让您的代码在多核时代翩翩起舞。 ####
|
20天前
|
中间件 Go API
使用Go语言构建高性能RESTful API
在现代软件开发中,RESTful API因其简洁和高效而成为构建网络服务的首选。Go语言以其并发处理能力和高性能著称,是开发RESTful API的理想选择。本文将介绍如何使用Go语言构建RESTful API,包括基础的路由设置、中间件的使用、数据验证、错误处理以及性能优化。通过实际代码示例,我们将展示Go语言在API开发中的强大功能和灵活性。
Go语言的条件控制语句及循环语句的学习笔记
本文是Go语言的条件控制语句和循环语句的学习笔记,涵盖了if语句、if-else语句、if嵌套语句、switch语句、select语句以及for循环和相关循环控制语句的使用方法。
Go语言的条件控制语句及循环语句的学习笔记
|
2月前
|
Go API 开发者
深入探讨:使用Go语言构建高性能RESTful API服务
在本文中,我们将探索Go语言在构建高效、可靠的RESTful API服务中的独特优势。通过实际案例分析,我们将展示Go如何通过其并发模型、简洁的语法和内置的http包,成为现代后端服务开发的有力工具。
|
2月前
|
存储 Go
Go: struct 结构体类型和指针【学习笔记记录】
本文是Go语言中struct结构体类型和指针的学习笔记,包括结构体的定义、成员访问、使用匿名字段,以及指针变量的声明使用、指针数组定义使用和函数传参修改值的方法。
|
2月前
|
人工智能 算法 搜索推荐
Go学习笔记-代码调
近年来,人工智能技术飞速发展,Cody作为由Sourcegraph开发的一款AI驱动编码助手,应运而生。它不仅提供代码预测与补全,还能深度理解代码上下文,为开发者提供准确建议,提升编码效率和质量。Cody能识别潜在错误并提出修复建议,缩短调试时间,同时进行智能代码审查,帮助优化代码结构和风格。未来,随着AI技术进步,Cody将不断学习优化,成为开发者不可或缺的伙伴,推动编程领域的创新与发展。
32 0
|
3月前
|
安全 Java 测试技术
Go 高性能编程心法探秘
文章深入探讨了Go语言在高性能编程中的各种技巧,包括常用数据结构的使用、内存管理、并发编程策略,以及如何通过减少锁的使用、有效利用sync包中的工具来优化程序性能。
19 0