阻止接收 channel

标签 go concurrency channel

我有以下 go 代码来等待流。预期的输出是:

line1
line2
line3
line4
line5
escape1
scan done
done....

但是在 line5 之后,我的代码一直挂起。

var lines = `
line1
line2
line3
line4
line5
line6
line7
`

func main() {
    var (
        donec  = make(chan struct{})
        stream = make(chan string, 5000)
        exitc  = make(chan struct{})
    )
    go func() {
        scanner := bufio.NewScanner(strings.NewReader(lines))
    escape1:
        for {
            for scanner.Scan() {
                select {
                case <-donec:
                    fmt.Println("escape1")
                    close(stream)
                    break escape1
                default:
                    stream <- scanner.Text()
                }
            }
        }
        close(exitc)
        fmt.Println("scan done")
        return
    }()

escape2:
    for {
        select {
        case txt, ok := <-stream:
            if !ok {
                fmt.Println("stream closed!")
            }
            fmt.Println(txt)
            if strings.Contains(txt, "line5") {
                close(donec)
                <-exitc
                break escape2
            }
        }
    }
    fmt.Println("done....")
}

认为我做的一切都是对的。谁能帮我调试这个挂起的代码?

谢谢!

最佳答案

我认为这是因为您的 escape1 for 循环包装了 for scanner.Scan() 循环。

当我删除外部 for 循环时,它对我来说工作正常:https://play.golang.org/p/NU3m3Deil7

func main() {
    var (
        donec  = make(chan struct{})
        stream = make(chan string, 5000)
        exitc  = make(chan struct{})
    )
    go func() {
        scanner := bufio.NewScanner(strings.NewReader(lines))
    escape1:
        for scanner.Scan() {
            select {
            case <-donec:
                fmt.Println("escape1")
                close(stream)
                break escape1
            default:
                stream <- scanner.Text()
            }
        }

        close(exitc)
        fmt.Println("scan done")
        return
    }()

escape2:
    for {
        select {
        case txt, ok := <-stream:
            if !ok {
                fmt.Println("stream closed!")
            }
            fmt.Println(txt)
            if strings.Contains(txt, "line5") {
                close(donec)
                <-exitc
                break escape2
            }
        }
    }
    fmt.Println("done....")
}

关于阻止接收 channel ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36272673/

相关文章:

java - 集群中分布式事务和/或数据共享的Java解决方案

Javascript 异步 promise 作为宏任务

c# - 从音频文件C#中提取信息

concurrency - N>1 goroutines 的不同结果(在 N>1 Cpu :s). 为什么?

json - 如何用 Go 结构体来表示这个复杂的数据结构?

go - 限制 FormFile 中的文件大小

go - Base64 编码不会因无效字符而失败

go - 为什么带有文件上传的 HTTP 请求在第一次请求时失败(仅)?

golang并发同步问题

api - D 中基于任务的并行性