Golang中如何实现函数锁定功能
Golang中如何实现函数锁定功能 请查看以上代码,我是否需要将digits函数放在互斥锁中,因为变量number在这些goroutine之间是共享的。
func main() {
var number int
var wg sync.WaitGroup
var mutex sync.Mutex
rand.Seed(time.Now().UnixNano())
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
mutex.Lock()
number = rand.Intn(100)
fmt.Printf("Number: %d\n", number)
digits(number)
mutex.Unlock()
}()
}
wg.Wait()
}
func digits(number int) {
var ds []int
for number > 0 {
ds = append(ds, number%10)
number = number / 10
}
fmt.Printf("Digits: %v\n", ds)
}
更多关于Golang中如何实现函数锁定功能的实战教程也可以访问 https://www.itying.com/category-94-b0.html
感谢回复…这是否意味着,在通道中它永远不会发生冲突。
更多关于Golang中如何实现函数锁定功能的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
感谢回复……这是否意味着,在通道中永远不会发生冲突?
如果没有你的"并发"计划/映射,不能100%断定它永远不会发生冲突。
然而我们可以100%确定的是,通道用于进程间的异步消息传递,其功能与互斥锁略有不同。所以在你的情况下,由于没有任何共享变量,只是在这里和那里传递输出,通道是最佳选择。
不,不需要。
因为您对 calcSquares 和 calcCubes 都使用了通道和委托机制。每当它们中的任何一个异步调用 digits 时,它们都有一个清晰且专用的通道来回复。此外,在这种情况下,使用通道比互斥锁更合理。做得好。
只有当多个进程读取或写入共享变量时,才需要使用互斥锁。例如,Go 的 map 不是线程安全的,因此如果有多个进程对同一个 map 对象进行读写操作,使用互斥锁比使用通道来同步 map 对象更合理。
在您提供的代码中,number 变量确实在多个 goroutine 之间共享,并且存在竞态条件。当前实现中,您将互斥锁应用于整个 goroutine 函数体,包括对 digits 函数的调用。然而,digits 函数本身是线程安全的,因为它只操作其参数 number 的副本,不访问共享状态。
以下是优化后的代码示例,将锁的范围缩小到仅保护共享变量 number 的读写:
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
func main() {
var number int
var wg sync.WaitGroup
var mutex sync.Mutex
rand.Seed(time.Now().UnixNano())
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
// 只锁定对共享变量 number 的读写
mutex.Lock()
number = rand.Intn(100)
localNumber := number // 创建局部副本
mutex.Unlock()
fmt.Printf("Number: %d\n", localNumber)
digits(localNumber) // 使用局部副本,无需锁保护
}()
}
wg.Wait()
}
func digits(number int) {
var ds []int
n := number // 保留原始值,避免修改参数
for n > 0 {
ds = append(ds, n%10)
n = n / 10
}
fmt.Printf("Digits: %v\n", ds)
}
关键改进点:
- 锁只保护对共享变量
number的赋值操作 - 创建局部变量
localNumber来保存number的当前值,这样digits函数可以无锁运行 - 在
digits函数内部使用局部变量n进行操作,避免修改函数参数
这种实现减少了锁的持有时间,提高了并发性能,同时仍然保证了数据竞争的安全性。

