Go语言代码示例
package main
import (
"fmt"
"sync"
)
// 定义服务器总积分
var totalScore int
func playerTask(playerID int, wg *sync.WaitGroup) {
defer wg.Done()
// 模拟玩家的移动、攻击等操作
fmt.Printf("Player %d is performing tasks...\n", playerID)
// 假设这些操作完成后会对总积分有影响,这里简单模拟增加10分
// 注意这里需要加锁防止竞争条件
mutex.Lock()
totalScore += 10
mutex.Unlock()
}
var mutex sync.Mutex
func main() {
numPlayers := 5
var wg sync.WaitGroup
wg.Add(numPlayers)
for i := 1; i <= numPlayers; i++ {
go playerTask(i, &wg)
}
wg.Wait()
fmt.Printf("All player tasks completed. Total score: %d\n", totalScore)
}
避免共享资源竞争条件的方法
- 使用互斥锁(Mutex):在对共享资源(如
totalScore
)进行读写操作时,通过mutex.Lock()
和mutex.Unlock()
来确保同一时间只有一个协程能够访问共享资源。这样就避免了多个协程同时修改共享资源导致的数据不一致问题。
- 读写锁(RWMutex):如果读操作远多于写操作,可以考虑使用读写锁。读操作时允许多个协程同时进行,写操作时则独占资源,从而提高并发性能。
WaitGroup协调任务顺序的原理
- Add方法:在启动每个玩家的并发任务前,通过
wg.Add(numPlayers)
将WaitGroup的计数器设置为玩家数量,即需要等待完成的任务数。
- Done方法:在每个玩家任务函数
playerTask
中,使用defer wg.Done()
,表示该任务已经完成,会将WaitGroup的计数器减1。
- Wait方法:
wg.Wait()
会阻塞主线程,直到WaitGroup的计数器变为0,即所有玩家的任务都调用了wg.Done()
。这样就确保了在所有玩家的相关任务完成后,才会继续执行后续对共享资源更新的操作(在示例代码中就是打印总积分)。