登录
首页 >  Golang >  Go问答

阻塞顺序的通道

来源:stackoverflow

时间:2024-03-13 18:54:26 345浏览 收藏

本篇文章给大家分享《阻塞顺序的通道》,覆盖了Golang的常见基础知识,其实一个语言的全部知识点一篇文章是不可能说完的,但希望通过这些问题,让读者对自己的掌握程度有一定的认识(B 数),从而弥补自己的不足,更好的掌握它。

问题内容

我试图了解通道在 golang 中是如何工作的。我的代码非常简单,但输出却令人惊讶。

正如文档所述:从通道读取和写入通道会阻塞当前的 goroutine,因此我认为写入通道会阻塞通道,直到主例程产生。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main
 
func rtn(messages chan<- string) {
    defer close(messages)
 
    println("p1")
    messages <- "ping1"
 
    //for i := 0; i < 10000000; i++ { }
 
    println("p2")
    messages <- "ping2"
}
 
func main() {
    messages := make(chan string)
    go rtn(messages)
 
    for msg := range messages {
        println(msg)
    }
}

我以为它会打印

1
2
3
4
p1
ping1
p2
ping2

但它实际上打印了

1
2
3
4
p1
p2
ping1
ping2

解决方案


您正在使用无缓冲通道,它作为主协程和第二协程之间的同步点。

在这种情况下,你只知道当第二个 goroutine 位于 messages <- "ping1" 时,主要的 goroutine 位于 for msg := range messages 行。因此,不能保证主循环立即到达 println(msg)。也就是说,与此同时,第二个 goroutine 可能已经继续前进并到达 println("p2")messages <- "ping2" 行。

作为反例,我添加一个通道只是为了强制打印之间的完全同步。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package main
 
func rtn(messages chan<- string, syncchan chan struct{}) {
    defer close(messages)
 
    println("p1")
    messages <- "ping1"
 
    //wait for main goroutine to print its message
    <-syncchan
 
    //for i := 0; i < 10000000; i++ { }
 
    println("p2")
    messages <- "ping2"
 
    //wait for main goroutine to print its message
    <-syncchan
}
 
func main() {
    messages := make(chan string)
    syncchan := make(chan struct{})
    go rtn(messages, syncchan)
 
    for msg := range messages {
        println(msg)
        //notify the second goroutine that is free to go
        syncchan <- struct{}{}
    }
}

它会打印您期望的输出:

1
2
3
4
p1
ping1
p2
ping2

这是另一个产生您正在寻找的输出的示例。在这种情况下,主 goroutine 被 time.sleep() 强制阻塞。这将使第二个 goroutine 在接收者准备好接收之前准备好发送。因此,发送方实际上会阻塞发送操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package main
 
import (
    "time"
)
 
func rtn(messages chan<- string) {
    defer close(messages)
 
    println("p1")
    messages <- "ping1"
 
    //for i := 0; i < 10000000; i++ { }
 
    println("p2")
    messages <- "ping2"
}
 
func main() {
    messages := make(chan string)
    go rtn(messages)
 
    //Put main goroutine to sleep. This will make the
    //sender goroutine ready before the receiver.
    //Therefore it will have to actually block!
    time.Sleep(time.Millisecond * 500)
 
    for msg := range messages {
        println(msg)
    }
}

今天关于《阻塞顺序的通道》的内容就介绍到这里了,是不是学起来一目了然!想要了解更多关于的内容请关注golang学习网公众号!

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>