go中实现简单自旋锁
package main
import (
"sync/atomic"
"time"
)
type SpinLock struct {
lock int32
}
func (sl *SpinLock) Lock() {
for !sl.TryLock() {
time.Sleep(1) // 等待并尝试获取锁
}
}
func (sl *SpinLock) Unlock() {
atomic.StoreInt32(&sl.lock, 0) // 释放锁
}
func (sl *SpinLock) TryLock() bool {
return atomic.CompareAndSwapInt32(&sl.lock, 0, 1) // 尝试获取锁
}
func main() {
var lock SpinLock
lock.Lock()
// critical section
lock.Unlock()
}
这个例子中的SpinLock结构体有一个int32类型的lock字段,用于表示锁的状态。Lock方法会不断尝试获取锁,直到成功为止。Unlock方法会释放锁。TryLock方法会尝试获取锁,如果成功则返回true,否则返回false。
请注意,自旋锁在某些情况下可能并不是最佳选择,因为它们会持续占用CPU资源直到获取到锁。在高并发或者长时间等待锁的情况下,使用标准的互斥锁(如sync.Mutex)可能会更加高效。自旋锁更适合锁保护的临界区很小,锁被持有的时间非常短的情况。在这种情况下,自旋锁的开销可能会小于创建和管理一个goroutine的开销。在使用自旋锁时,需要仔细考虑其适用场景。
在Go语言中实现自旋锁时,runtime.Gosched()通常是一个更好的选择。runtime.Gosched()函数会让当前goroutine让出CPU,从而允许其他goroutine运行。这样可以避免当前goroutine占用过多CPU资源。
在 Go 语言中,runtime.Gosched() 函数的作用是让当前 goroutine 让出 CPU,以便其他的 goroutine 获得执行的机会1。其原理是将当前 Goroutine 放回到队列中,等待下一次调度。
package main
import (
"fmt"
"runtime"
"time"
)
func main() {
go func() {
for i := 0; i < 3; i++ {
fmt.Println("Goroutine 1 is running,", i)
runtime.Gosched()
}
}()
go func() {
for i := 0; i < 3; i++ {
fmt.Println("Goroutine 2 is running,", i)
runtime.Gosched()
}
}()
time.Sleep(100 * time.Millisecond)
}