Golang Go语言中如何打印出“End. [sender]”

大家好,这是我的代码:

func main () {
    // synChan := make(chan struct{}, 1)
    intChan := make(chan int, 1)
    ticker := time.NewTicker(time.Second)
    go func() {
        for range ticker.C {
            select {
            case intChan <- 1:
            case intChan <- 2:
            case intChan <- 3:
            }
        }
        // synChan<- struct{}{}
        fmt.Println("End [SEND]")
    }()
var sum int

for e := range intChan {
    fmt.Printf("接收到  %d\n", e)
    sum += e
    if sum &gt; 3 {
        fmt.Println(sum)
        break
    }
}

fmt.Println("End [REC]")

// &lt;-synChan

}

这是《 GO 并发编程》里讲通道的一个题目,但是我试了几个方法之后会成死锁,请问大家如何打印出这个 fmt.Println("End [SEND]")。这里为什么不能打印出来?我想过是 main 函数退出了,所以试着使用通道阻塞,但直接会出死锁。。。


Golang Go语言中如何打印出“End. [sender]”

更多关于Golang Go语言中如何打印出“End. [sender]”的实战教程也可以访问 https://www.itying.com/category-94-b0.html

10 回复

我蛮帮你问了大模型,你试试看:

这段 Go 代码的主要问题是,它在等待一个信号来表明发送 goroutine 已经结束,但是这个信号从未被发送。当sum大于 3 时,接收循环会中断,但是发送 goroutine 会因为intChan的缓冲区已满而阻塞,导致无法到达打印"End [SEND]"的代码行。

要解决这个问题,你需要确保发送 goroutine 有机会发送完成信号。在这个场景中,你可以通过关闭intChan来实现,因为关闭一个通道会导致所有接收者收到一个零值,并且随后的接收都会立即返回零值,而不会阻塞。因为intChan是一个 int 类型的通道,接收者会得到一个0

以下是修正后的代码,它确保了打印出"End [SEND]"

go<br>package main<br><br>import (<br> "fmt"<br> "time"<br>)<br><br>func main() {<br> intChan := make(chan int, 1)<br> ticker := time.NewTicker(time.Second)<br> done := make(chan struct{}) // 添加一个完成通道<br><br> go func() {<br> for range ticker.C {<br> select {<br> case intChan &lt;- 1:<br> case intChan &lt;- 2:<br> case intChan &lt;- 3:<br> }<br> }<br> ticker.Stop() // 停止 ticker<br> close(intChan) // 关闭 intChan<br> fmt.Println("End [SEND]")<br> close(done) // 发送完成信号<br> }()<br><br> var sum int<br><br> for e := range intChan {<br> fmt.Printf("接收到 %d\n", e)<br> sum += e<br> if sum &gt; 3 {<br> fmt.Println(sum)<br> break<br> }<br> }<br><br> fmt.Println("End [REC]")<br><br> &lt;-done // 等待发送 goroutine 完成<br>}<br>

这里做了以下改动:

1. 添加了一个done通道,用来接收发送 goroutine 完成的信号。
2. ticker.Stop()被调用来停止 ticker ,避免资源泄露。
3. 在发送循环结束后关闭intChan通道。
4. 打印"End [SEND]"后,关闭done通道来发送一个完成信号。
5. 在主函数的最后,添加&lt;-done来等待发送 goroutine 完成。

现在程序会等待发送 goroutine 结束后,才结束main函数,确保"End [SEND]"被打印出来。请注意,这个版本的代码假设发送 goroutine 总是会结束,否则可能会导致死锁。在实际编程中,你可能需要添加超时或其他机制来处理这种情况。

更多关于Golang Go语言中如何打印出“End. [sender]”的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


#1 这个 ai 的答案你试过没有,这里是禁止搬运 ai 回答的,

不行,死锁了

time.NewTicker 是创建了一个周期定时器,下面没有调用 ticker.Stop()来终止定时器,所以 for range ticker.C 回一直循环不会退出

你这个不叫死锁好吧,你要在适当的时候调用 ticker.Stop()让这个 Ticker 停下来,让 channel 被 close

你接收完数据了,不向发送方发送结束命令,它还在发数据呢

ticker.Stop() 停止计时器后只是不再发送数据,但是 channel 并没有被关闭
https://pkg.go.dev/time#Ticker.Stop

<br>func main() {<br> intChan := make(chan int, 1)<br> ticker := time.NewTicker(time.Second)<br> end := make(chan int)<br> go func() {<br> loop:<br> for range ticker.C {<br> select {<br> case intChan &lt;- 1:<br> case intChan &lt;- 2:<br> case intChan &lt;- 3:<br> case &lt;-end:<br> fmt.Println("End [SEND]")<br> ticker.Stop()<br> break loop<br> }<br> }<br> }()<br><br> var sum int<br><br> for e := range intChan {<br> fmt.Printf("接收到 %d\n", e)<br> sum += e<br> if sum &gt; 3 {<br> fmt.Println(sum)<br> end &lt;- 1<br> break<br> }<br> }<br> fmt.Println("End [REC]")<br>}<br>

soga ,我懂了,谢谢大佬

抱歉抱歉

在Go语言中,打印输出到控制台通常使用标准库中的fmt包。要打印出字符串“End. [sender]”,你可以使用fmt.Printf函数来格式化输出,或者使用fmt.Sprintf先生成字符串再打印。这里,[sender]部分需要替换为具体的发送者信息。假设sender是一个变量,以下是两种方法的示例:

方法一:使用fmt.Printf直接打印

package main

import (
    "fmt"
)

func main() {
    sender := "Alice" // 假设发送者是Alice
    fmt.Printf("End. [%s]\n", sender)
}

方法二:使用fmt.Sprintf生成字符串后打印

package main

import (
    "fmt"
)

func main() {
    sender := "Bob" // 假设发送者是Bob
    message := fmt.Sprintf("End. [%s]", sender)
    fmt.Println(message)
}

在这两个例子中,%s是一个占位符,用于表示一个字符串。fmt.Printffmt.Sprintf会将sender变量的值替换到%s的位置。fmt.Printf直接输出到标准输出,而fmt.Sprintf返回一个格式化后的字符串,你可以将其赋值给变量或进一步处理。

根据你的需求选择合适的方法即可。如果你的sender变量已经存在,并且你需要动态地构建和打印这条消息,这两种方法都非常有效。

回到顶部