同步
sync
包提供了基础的同步原语,如互斥锁。除了 Once
和 WaitGroup
类型外,大多数都是供给底层库使用的。高层的同步最好通过通道通信完成。
Once
sync.Once
类型确保一个函数只被执行一次,无论有多少个 goroutine 调用它。这对于希望执行一些初始化或设置的场景非常有用。
package main
import (
"fmt"
"sync"
"time"
)
var (
initialized bool
initOnce sync.Once
)
func initialize() {
fmt.Println("Initializing...")
// 在这里执行初始化任务
initialized = true
}
func performTask() {
// sync.Once.Do 传递的函数只会被执行一次,
// 即使有多个 goroutine 调用它。
initOnce.Do(initialize)
// 在这里执行实际任务
fmt.Println("Performing the task...")
}
func main() {
// 在多个 goroutine 中运行 performTask
for i := 0; i < 5; i++ {
go performTask()
}
fmt.Println("Waiting for tasks to complete...")
time.Sleep(2 * time.Second)
}
// =>
// Waiting for tasks to complete...
// Initializing...
// Performing the task...
// Performing the task...
// Performing the task...
// Performing the task...
// Performing the task...
WaitGroups
sync.WaitGroup
用于等待一组 goroutine 完成它们的执行。
package main
import (
"fmt"
"sync"
"time"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done() // 当 goroutine 完成时减少计数器
fmt.Printf("Worker %d started\n", id)
time.Sleep(time.Second) // 模拟一些工作
fmt.Printf("Worker %d completed\n", id)
}
func main() {
var wg sync.WaitGroup
numWorkers := 3
for i := 1; i <= numWorkers; i++ {
wg.Add(1) // 在启动新 goroutine 之前递增计数器
go worker(i, &wg)
}
// 等待所有 goroutine 完成
wg.Wait()
fmt.Println("All workers have completed.")
}
// =>
// Worker 3 started
// Worker 1 started
// Worker 2 started
// Worker 3 completed
// Worker 2 completed
// Worker 1 completed
// All workers have completed.
原子计数器
sync/atomic
包提供了基本类型的原子操作,包括原子计数器。
原子操作对于在并发程序中无锁管理共享状态是至关重要的。
package main
import (
"fmt"
"sync"
"sync/atomic"
"time"
)
func incrementCounter(counter *int64, wg *sync.WaitGroup) {
defer wg.Done()
for i := 0; i < 10000; i++ {
// 原子地增加计数器
atomic.AddInt64(counter, 1)
}
time.Sleep(5 * time.Millisecond)
}
func main() {
var counter int64
var wg sync.WaitGroup
numGoroutines := 5
for i := 0; i < numGoroutines; i++ {
wg.Add(1)
go incrementCounter(&counter, &wg)
}
wg.Wait()
fmt.Println("Final Counter Value:", atomic.LoadInt64(&counter))
}
// => Final Counter Value: 50000
互斥锁
互斥锁(mutex, 即 mutual exclusion)是一种同步原语,用于保护共享数据,防止多个 goroutine 同时访问时引发冲突。
package main
import (
"fmt"
"sync"
)
type Counter struct {
value int
mu sync.Mutex
}
func (c *Counter) Increment() {
c.mu.Lock()
defer c.mu.Unlock()
c.value++
}
func (c *Counter) GetValue() int {
c.mu.Lock()
defer c.mu.Unlock()
return c.value
}
func main() {
var wg sync.WaitGroup
counter := Counter{}
numGoroutines := 5
for i := 0; i < numGoroutines; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for j := 0; j < 10000; j++ {
counter.Increment()
}
}()
}
wg.Wait()
fmt.Println("Final Counter Value:", counter.GetValue())
}
// => Final Counter Value: 50000
互斥锁适用于保护复杂的共享资源、临界区或需要对锁进行精细控制的场景。而原子计数器适用于简单场景,比如共享的资源是个简单计数器或标志的情况。
代码挑战
使用互斥锁实现一个可以被多个 goroutine 安全地递增和递减的并发计数器。
Loading...
> 此处输出代码运行结果