为了账号安全,请及时绑定邮箱和手机立即绑定

Golang 中的 channel 和 mutex 有什么区别?

Golang 中的 channel 和 mutex 有什么区别?

Go
倚天杖 2022-06-01 11:36:45
我听说这channel比sycn.Mutex.Lock()您的程序具有高并发性时要好。但是为什么渠道更有效率呢?在我看来,要实现一个安全的缓冲池(我认为通道可以被认为是一个缓冲池),你必须使用锁。如果channel效率更高,为什么会有sycn.Mutex?因为我可以编写下面的代码来模拟sync.Mutex.type seme struct {    lock chan int    locked bool}func (l *seme)Lock() {// state 0 for initial, 1 for locked, 2 for free.    if atomic.CompareAndSwapInt32(&l.state, 0, 1) {        l.lock = make(chan int, 1)    }    l.lock <- 0    l.state = 1}func (l *seme)UnLock() {    if !atomic.CompareAndSwapInt32(&l.state, 1, 2)  {        panic("UnLock a free Lock")    }    l.state = 2    <- l.lock}如果channel到处都比mutex,我为什么要使用mutex?也就是说,我应该什么时候使用mutex而不是channel?有人可以给我一个例子吗?
查看完整描述

2 回答

?
catspeake

TA贡献1111条经验 获得超0个赞

通道从根本上不同于互斥体。


一个有足够细节的正确答案会太长,所以让我们只介绍主要亮点,特别是在 Go 频道方面:


Go 通道提供并发例程(goroutines)之间的类型化数据传输。

A为并发例程(goroutines)之间的共享内存sync.Mutex提供互斥。

数据传输表示复制某个类型 T 的值。Goroutine A 将一个值放入通道中:


var v T  // v is a value of type T

...

ch <- v  // put v's value into the channel

何时以及是否尝试放入v 通道块,以及如果您愿意,您可以对此做些什么,有点复杂,但如果通道是缓冲的,那么至少一些值可以立即进入它而没有任何阻塞,以便发送 goroutine 可以继续。如果通道是无缓冲的,则发送方会阻塞,直到某个接收方 goroutine 正在积极等待一个值。(有时这是可取的,有时则不是。)


同时,goroutine B 从通道中取出一个值:


var w T  // w is also a value of type T

...

w <- ch

要不就:


w :=<- ch

同样,何时以及是否会阻塞,您可以做什么,何时应该做某事等,可能会变得复杂;但在简单的情况下,这会等待有一个可用的值——让某个 goroutine 执行ch <- v,或者如果通道被缓冲,则已经完成它——然后它将放入w通道中的值复制到变量中。变量v可能已经改变,甚至被完全破坏。该值已安全地存储在通道中,现在已从通道中删除并放入变量w中。


Go 通道有一些额外的功能,例如关闭通道的能力,它可以防止进一步的写入,并将“数据结束”通知传递给读取操作。这可以通过单值读取 ( ) 进行测试,并在循环w, ok <- ch中进行隐式测试。for w := range ch


sync.Mutex相比之下,实例只是让您调用Lockand Unlock。它不保存任何排队的值(如缓冲通道那样),甚至没有一种类型(除了sync.Mutex它自己),可以防止您意外地将 a 发送float到期望的东西string或其他东西。这个锁的存在让两个或多个 goroutine 使用共享内存区域来完成某些事情。


通道的运行时实现很可能需要某种互斥锁。这不一定是sync.Mutex它本身:任何提供足够互斥的东西就足够了。在您可能正在使用的 Go 通道实现中,它不是一个专门的运行时互斥锁sync.Mutex,而是一个专用的运行时互斥锁。(请注意,此链接指向特定行,并且该行可能会随着时间的推移而过时。)由于某些通道代码是由编译器本身直接生成的,因此不应假定此处的运行时例程正在使用:您的编译器可能与众不同。然而,研究这个特定的实现可能会让您对您可以使用通道做什么有所启发。


互斥锁通常比通道简单得多。要查看示例,请将上述通道实现中的代码量(不包括编译器的内联插入)与此特定 Go 实现的sync.Mutex源代码进行比较。


查看完整回答
反对 回复 2022-06-01
?
呼唤远方

TA贡献1856条经验 获得超11个赞

在 Golang 的并发程序中有两种通信方式。

  1. 同步包:通过共享内存进行通信。

  2. 渠道:通过交流共享记忆。

去推荐

不要通过共享内存进行通信。相反,通过通信共享内存。


查看完整回答
反对 回复 2022-06-01
  • 2 回答
  • 0 关注
  • 201 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信