关于go的channel阻塞问题

发布于 2022-09-04 02:50:37 字数 1433 浏览 12 评论 0

在看go入门指南时遇到一个问题,下面的程序为什么会产生死锁。

package main

import (
    "fmt"
)

func f1(in chan int) {
    fmt.Println(<-in)
}

func main() {
    out := make(chan int)
    out <- 2
    go f1(out)
}

书中说到:通道的发送/接收操作在对方准备好之前是阻塞的:,按理说,out <- 2等到fmt.Println(<-in)准备好就可以执行了,不应该产生死锁啊,求解
但是,当我调整了一下顺序,就可以了

func f1(in chan int) {
    fmt.Println(<-in)
}

func main() {
    out := make(chan int)
    go f1(out)
    out <- 2
}
// 结果:
2

然后在调整一点

func f1(in chan int) {
    in <- 2
    fmt.Println("in")
}

func main() {
    out := make(chan int)
    <-out
    go f1(out)
}
// 结果依然是死锁

如果此时和上面一样调整一下顺序

func f1(in chan int) {
    in <- 2
    fmt.Println("in")
}

func main() {
    out := make(chan int)
    go f1(out)
    <-out
}
// 结果为 in

我又尝试了一下

func f1(in chan int) {
    in <- 2
    fmt.Println("in")
}

func main() {
    out := make(chan int)
    <-out
    fmt.Println("out")
    go f1(out)
}

此时的结果是死锁,还有一个关键的点是:没有打印出out
我猜:是不是由于在执行<-out时阻塞,而此时只有一个协程,并没有执行go f1(out),所以导致channel的双方并没有准备好,进而产生了死锁。不知道对不对,好纠结???

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

恋竹姑娘 2022-09-11 02:50:37

https://segmentfault.com/q/10...

完全一样的问题……

package main

import (
    "fmt"
)

func f1(in chan int) {
    fmt.Println(<-in)
}

func main() {
    out := make(chan int)
    out <- 2
    go f1(out)
}

有啥好纠结的……

记住一点,单纯的out<-和<-in都会阻塞,只有两个同时进行了,才能继续执行。

这里你看上去有个协程,来执行<-in,但是实际上已经阻塞在out<-2了,协程没办法执行下去……

解决办法就两个,要么在out <- 2之前开一个协程去消费这个channel,

要么就给这个channel加个大小,让他里面默认能存1个数据,这样才不会阻塞,即:make(chan int, 1)

書生途 2022-09-11 02:50:37

Channel communication

Channel communication is the main method of synchronization between goroutines. Each send on a particular channel is matched to a corresponding receive from that channel, usually in a different goroutine.

A send on a channel happens before the corresponding receive from that channel completes.

This program:

var c = make(chan int, 10)
var a string

func f() {

a = "hello, world"
c <- 0

}

func main() {

go f()
<-c
print(a)

}
is guaranteed to print "hello, world". The write to a happens before the send on c, which happens before the corresponding receive on c completes, which happens before the print.

The closing of a channel happens before a receive that returns a zero value because the channel is closed.

In the previous example, replacing c <- 0 with close(c) yields a program with the same guaranteed behavior.

A receive from an unbuffered channel happens before the send on that channel completes.

This program (as above, but with the send and receive statements swapped and using an unbuffered channel):

var c = make(chan int)
var a string

func f() {

a = "hello, world"
<-c

}
func main() {

go f()
c <- 0
print(a)

}
is also guaranteed to print "hello, world". The write to a happens before the receive on c, which happens before the corresponding send on c completes, which happens before the print.

If the channel were buffered (e.g., c = make(chan int, 1)) then the program would not be guaranteed to print "hello, world". (It might print the empty string, crash, or do something else.)

The kth receive on a channel with capacity C happens before the k+Cth send from that channel completes.

This rule generalizes the previous rule to buffered channels. It allows a counting semaphore to be modeled by a buffered channel: the number of items in the channel corresponds to the number of active uses, the capacity of the channel corresponds to the maximum number of simultaneous uses, sending an item acquires the semaphore, and receiving an item releases the semaphore. This is a common idiom for limiting concurrency.

This program starts a goroutine for every entry in the work list, but the goroutines coordinate using the limit channel to ensure that at most three are running work functions at a time.

var limit = make(chan int, 3)

func main() {

for _, w := range work {
    go func(w func()) {
        limit <- 1
        w()
        <-limit
    }(w)
}
select{}

}

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文