Go

Go 知识量:6 - 35 - 115

6.1 分布式锁><

进程内加锁- 6.1.1 -

在Go语言中,可以使用互斥锁(Mutex)来实现进程内的加锁。互斥锁是一种同步原语,用于保护共享资源,确保在任何时刻只有一个goroutine可以访问共享资源。

下面是一个使用互斥锁实现进程内加锁的示例:

package main  
  
import (  
 "fmt"  
 "sync"  
)  
  
var (  
 counter int  
 mutex   sync.Mutex  
)  
  
func increment() {  
 mutex.Lock() // 加锁  
 defer mutex.Unlock() // 解锁  
  
 counter++  
 fmt.Println("Incremented counter:", counter)  
}  
  
func main() {  
 var wg sync.WaitGroup  
 for i := 0; i < 10; i++ {  
 wg.Add(1)  
 go func() {  
 defer wg.Done()  
 increment()  
 }()  
 }  
 wg.Wait()  
 fmt.Println("Final counter:", counter)  
}

在上面的示例中,定义了一个全局变量counter用于计数,并使用sync.Mutex类型创建了一个互斥锁mutex。在increment()函数中,使用mutex.Lock()方法对互斥锁进行加锁操作,以确保同一时刻只有一个goroutine可以执行该函数。在函数执行完毕后,使用defer mutex.Unlock()来解锁互斥锁。

在main()函数中,使用sync.WaitGroup来等待所有的goroutine执行完毕。通过调用wg.Add(1)来增加等待组的计数,然后在每个goroutine中调用defer wg.Done()来减少等待组的计数。最后,调用wg.Wait()等待所有goroutine执行完毕。

运行上述代码,将看到每个goroutine按顺序打印出计数值,并且在最后输出最终的计数值。这样可以确保counter变量的并发访问是安全的。

尝试锁- 6.1.2 -

尝试锁是一种非阻塞锁,它允许尝试加锁而不阻塞调用线程。如果锁已经被其他线程持有,尝试锁会立即返回一个失败的结果,而不会使当前线程进入等待状态。

在Go语言中,可以使用sync.TryLock函数来实现尝试锁。该函数接受一个互斥锁作为参数,并返回一个布尔值表示是否成功获取了锁。如果获取成功,则返回true,否则返回false。

下面是一个使用尝试锁的示例:

package main  
  
import (  
 "fmt"  
 "sync"  
)  
  
var (  
 counter int  
 mutex   sync.Mutex  
)  
  
func increment() {  
 mutex.Lock() // 加锁  
 defer mutex.Unlock() // 解锁  
  
 counter++  
 fmt.Println("Incremented counter:", counter)  
}  
  
func main() {  
 var wg sync.WaitGroup  
 for i := 0; i < 10; i++ {  
 wg.Add(1)  
 go func() {  
 defer wg.Done()  
 increment()  
 }()  
 }  
 wg.Wait()  
 fmt.Println("Final counter:", counter)  
}

在上述示例中,使用sync.Mutex作为互斥锁,并使用TryLock()方法尝试获取锁。如果获取成功,则执行需要加锁的代码逻辑,并在完成后使用defer mutex.Unlock()释放锁。如果获取锁失败,则直接输出"Failed to get the lock."。

使用尝试锁可以避免线程阻塞,提高并发性能。它适用于那些不需要等待锁释放的场景,或者在等待时间较长时可以采取其他策略的情况。

如何选择合适的锁- 6.1.3 -

在Go语言中,选择合适的锁取决于具体需求和场景。以下是一些常见的锁选择:

  • 互斥锁(Mutex): 互斥锁是最基本的锁机制,用于保护共享资源,确保在任何时刻只有一个goroutine可以访问共享资源。可以使用sync.Mutex来实现互斥锁。

  • 读写锁(RWMutex): 读写锁允许多个goroutine同时读取共享资源,但在写入时只允许一个goroutine访问。这可以提高并发性能,特别是对于读操作远多于写操作的场景。可以使用sync.RWMutex来实现读写锁。

  • 尝试锁(TryLock): 尝试锁允许尝试加锁而不阻塞调用线程。如果加锁成功,则执行后续流程;如果加锁失败,则不会阻塞,而是直接返回加锁的结果。可以使用sync.TryLock函数来实现尝试锁。

  • 乐观锁(Optimistic Locking): 乐观锁假设冲突较少,只在更新时检查是否存在冲突。如果更新时发现冲突,则需要进行重试或回滚操作。乐观锁适用于读多写少的场景,可以减少锁的竞争和阻塞。

  • 分段锁(Segmented Lock): 分段锁将共享资源划分为多个段,并为每个段分配一个独立的锁。这样可以减少锁的竞争和阻塞,提高并发性能。

  • 分布式锁(Distributed Lock): 分布式锁适用于分布式系统中的多个节点访问共享资源的情况。它需要在整个系统中协调和管理锁的获取和释放,以确保一致性和互斥性。

选择合适的锁需要考虑并发访问的模式、读/写比例、锁的粒度、系统的规模和复杂性等因素。