【发布时间】:2022-01-07 12:52:12
【问题描述】:
在过去的几周里,我一直在努力解决一个(不那么)简单的问题:
什么时候最好使用sync.Mutex,相反,什么时候最好使用chan?
似乎对于很多问题,任何一种策略都可以与另一种策略互换 - 这就是问题所在!
使用 Golang 文档中的 this video。下面,我冒昧地在操场上指定代码并将其转换为 sync.Mutex 等效项。
是否存在某种问题(在现实世界中遇到)需要相互使用?
注意事项:
- 我是this use of chan 的忠实粉丝,我很难想出一个使用sync.Mutex 的更优雅的实现。
- 值得注意的是,
chan实现可以同时完成更多工作(达到 12 个)*
游乐场:
与chan 打乒乓球:
package main
import (
"fmt"
"time"
)
type Ball struct { hits int }
func main() {
table := make(chan *Ball)
go player("ping", table)
go player("pong", table)
table <- new(Ball)
time.Sleep(1 * time.Second)
<-table
}
func player(name string, table chan *Ball) {
for {
ball := <-table
ball.hits++
fmt.Println(name, ball.hits)
time.Sleep(100 * time.Millisecond)
table <- ball
}
}
与sync.Mutex 打乒乓球:
package main
import (
"fmt"
"time"
"sync"
)
type Ball struct { hits int }
var m = sync.Mutex{}
func main() {
ball := new(Ball)
go player("ping", ball)
go player("pong", ball)
time.Sleep(1 * time.Second)
}
func player(name string, ball *Ball) {
for {
m.Lock()
ball.hits++
fmt.Println(name, ball.hits)
time.Sleep(100 * time.Millisecond)
m.Unlock()
}
}
【问题讨论】:
-
这些是不同的工具。互斥锁对资源的访问顺序化。另一方面,通道用于协调 goroutine 之间的计算。当我们谈论 Mutex 时,可以使用毫无意义的通道来完成大量模式。例如,当我们关闭通道时,通道可以帮助构建将停止的管道。或者像扇入和扇出这样的模式。或者有 M:N 的工作派遣。
-
您设计的与两者相对相似的示例是规则的例外。通常很清楚您需要“互斥”而不是同步和通信。当有疑问时,更简单的实现通常是您想要的。
-
您还应该注意,您的示例实现不会做同样的事情。通道实现协调“乒乓”来回发送消息,而互斥锁实现只是提供围绕球变量的互斥,这导致没有确定性的排序。
标签: go concurrency