从接收通道进行阻塞

huangapple go评论89阅读模式
英文:

Go blocking from receiving 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....")
}

我认为我做得没错。有人可以帮我调试这个挂起的代码吗?

谢谢!

英文:

I have the following go code to wait for streams. The expected output is:

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

But after line5, my code keeps hanging.

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 &lt;-donec:
                    fmt.Println(&quot;escape1&quot;)
                    close(stream)
                    break escape1
                default:
                    stream &lt;- scanner.Text()
                }
            }
        }
        close(exitc)
        fmt.Println(&quot;scan done&quot;)
        return
    }()

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

Think I am doing everything right. Could anybody help me debug this hanging code?

Thanks!

答案1

得分: 1

我认为问题出在你的 escape1 循环包裹了 for scanner.Scan() 循环。

当我移除外部的循环后,代码在我这里可以正常工作: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....")
}

请注意,我只是翻译了你的代码,并没有回答你的问题。

英文:

I think it's because your escape1 for loop wraps the for scanner.Scan() loop.

When I remove that outer for loop it works fine for me: 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 &lt;-donec:
				fmt.Println(&quot;escape1&quot;)
				close(stream)
				break escape1
			default:
				stream &lt;- scanner.Text()
			}
		}

		close(exitc)
		fmt.Println(&quot;scan done&quot;)
		return
	}()

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

huangapple
  • 本文由 发表于 2016年3月29日 07:03:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/36272673.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定