为什么这些 goroutines 不阻塞?
Why don't these goroutines block?
我希望这两个 goroutine 会因为以下原因而永远阻塞,但事实并非如此。为什么?
频道没有缓冲区,将等待receive()
接收。
send()
持有锁,因此 receive()
中的 num := <-s.ch
没有机会执行。
永远阻止[=15=]
怎么了?
package main
import (
"sync"
"fmt"
)
type S struct {
mu sync.Mutex
ch chan int
wg sync.WaitGroup
}
func (s *S) send() {
s.mu.Lock()
s.ch <- 5
s.mu.Unlock()
s.wg.Done()
}
func (s *S) receive() {
num := <-s.ch
fmt.Printf("%d\n", num)
s.wg.Done()
}
func main() {
s := new(S)
s.ch = make(chan int)
s.wg.Add(2)
go s.send()
go s.receive()
s.wg.Wait()
}
您的 receive()
方法不使用锁,因此 send()
持有锁对 receive()
没有影响。
并且由于 send()
和 receive()
运行 在他们自己的 goroutine 中,send()
将到达发送值 5
的位置在通道上,因此 receive()
中的接收可以继续,并且会在下一行打印出来。
另请注意,要使用来自多个 goroutine 的通道,您不需要 "external" 同步。通道对于并发使用是安全的,数据竞争不会因设计而发生。有关详细信息,请参阅
如果receive()
方法也会像这样使用锁:
func (s *S) receive() {
s.mu.Lock()
num := <-s.ch
s.mu.Unlock()
fmt.Printf("%d\n", num)
}
那么是的,不会打印任何内容,因为在 send()
释放锁之前接收不会发生,但在有人从频道接收之前不会发生。
在这种情况下,程序将在 1 秒后终止而不打印任何内容,因为当睡眠结束时,主 goroutine 结束,整个应用程序也会随之结束。它不会等待其他非主 goroutines 完成。有关详细信息,请参阅 。
编辑:
是的,你对锁的理解有误。锁定 sync.Mutex
只会锁定互斥锁值本身,它不会锁定整个结构值(它不能)。 "locks the value itself" 意味着如果另一个 goroutine 也调用它的 Mutex.Lock()
方法,该调用将阻塞,直到通过调用它的 Mutex.Unlock()
方法释放锁。解锁后,在 Mutex.Lock()
调用时阻塞的 goroutine 将继续锁定互斥锁和 return.
我希望这两个 goroutine 会因为以下原因而永远阻塞,但事实并非如此。为什么?
频道没有缓冲区,将等待
receive()
接收。send()
持有锁,因此receive()
中的num := <-s.ch
没有机会执行。永远阻止[=15=]
怎么了?
package main
import (
"sync"
"fmt"
)
type S struct {
mu sync.Mutex
ch chan int
wg sync.WaitGroup
}
func (s *S) send() {
s.mu.Lock()
s.ch <- 5
s.mu.Unlock()
s.wg.Done()
}
func (s *S) receive() {
num := <-s.ch
fmt.Printf("%d\n", num)
s.wg.Done()
}
func main() {
s := new(S)
s.ch = make(chan int)
s.wg.Add(2)
go s.send()
go s.receive()
s.wg.Wait()
}
您的 receive()
方法不使用锁,因此 send()
持有锁对 receive()
没有影响。
并且由于 send()
和 receive()
运行 在他们自己的 goroutine 中,send()
将到达发送值 5
的位置在通道上,因此 receive()
中的接收可以继续,并且会在下一行打印出来。
另请注意,要使用来自多个 goroutine 的通道,您不需要 "external" 同步。通道对于并发使用是安全的,数据竞争不会因设计而发生。有关详细信息,请参阅
如果receive()
方法也会像这样使用锁:
func (s *S) receive() {
s.mu.Lock()
num := <-s.ch
s.mu.Unlock()
fmt.Printf("%d\n", num)
}
那么是的,不会打印任何内容,因为在 send()
释放锁之前接收不会发生,但在有人从频道接收之前不会发生。
在这种情况下,程序将在 1 秒后终止而不打印任何内容,因为当睡眠结束时,主 goroutine 结束,整个应用程序也会随之结束。它不会等待其他非主 goroutines 完成。有关详细信息,请参阅
编辑:
是的,你对锁的理解有误。锁定 sync.Mutex
只会锁定互斥锁值本身,它不会锁定整个结构值(它不能)。 "locks the value itself" 意味着如果另一个 goroutine 也调用它的 Mutex.Lock()
方法,该调用将阻塞,直到通过调用它的 Mutex.Unlock()
方法释放锁。解锁后,在 Mutex.Lock()
调用时阻塞的 goroutine 将继续锁定互斥锁和 return.