如何高效关闭两个goroutines?

我正在使用两个并发 goroutine 将 stdin/stdout 从我的终端复制到 net.Conn 目标。出于某种原因,我无法在不出现恐慌错误的情况下完全停止这两个 go 例程(用于尝试关闭已关闭的连接)。这是我的代码:


func interact(c net.Conn, sessionMap map[int]net.Conn) {

    quit := make(chan bool) //the channel to quit


    copy := func(r io.ReadCloser, w io.WriteCloser) {

        defer func() {

            r.Close()

            w.Close()

            close(quit) //this is how i'm trying to close it

        }()


        _, err := io.Copy(w, r)


        if err != nil {

            //

        }


    }


    go func() {

        for {

            select {

            case <-quit:

                return

            default:

                copy(c, os.Stdout)

            }

        }

    }()


    go func() {

        for {

            select {

            case <-quit:

                return

            default:

                copy(os.Stdin, c)

            }

        }

    }()

}

这个错误是因为panic: close of closed channel

我想终止两个 go 例程,然后通常继续执行另一个函数。我究竟做错了什么?


GCT1015
浏览 125回答 2
2回答

摇曳的蔷薇

你不能close多次调用一个通道,没有理由调用copyfor 循环,因为它只能运行一次,而且你正在向错误的方向复制,写入标准输入并从标准输出读取。简单地询问如何退出 2 个 goroutines 很简单,但这不是您在这里需要做的唯一事情。由于io.Copy是阻塞,您不需要额外的同步来确定调用何时完成。这使您可以显着简化代码,从而更容易推理。func interact(c net.Conn) {&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; // You want to close this outside the goroutine if you&nbsp; &nbsp; &nbsp; &nbsp; // expect to send data back over a half-closed connection&nbsp; &nbsp; &nbsp; &nbsp; defer c.Close()&nbsp; &nbsp; &nbsp; &nbsp; // Optionally close stdout here if you need to signal the&nbsp; &nbsp; &nbsp; &nbsp; // end of the stream in a pipeline.&nbsp; &nbsp; &nbsp; &nbsp; defer os.Stdout.Close()&nbsp; &nbsp; &nbsp; &nbsp; _, err := io.Copy(os.Stdout, c)&nbsp; &nbsp; &nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }()&nbsp; &nbsp; _, err := io.Copy(c, os.Stdin)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; //&nbsp; &nbsp; }}另请注意,您可能无法跳出io.Copyfrom stdin,因此您不能指望函数interact返回。在函数体中手动执行io.Copy并检查每个循环的半关闭连接可能是个好主意,这样您就可以更快地退出并确保完全关闭net.Conn.

慕运维8079593

也可以是这样的&nbsp;func scanReader(quit chan int, r io.Reader) chan string {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; line := make(chan string)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;go func(quit chan int) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; defer close(line)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; scan := bufio.NewScanner(r)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for scan.Scan() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; select {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;case <- quit:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;default:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; s := scan.Text()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; line <- s&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }(quit)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return line&nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; stdIn := scanReader(quit, os.Stdin)&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; conIn := scanReader(quit, c)&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; select {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case <-quit:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case l <- stdIn:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _, e := fmt.Fprintf(c, l)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if e != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;quit <- 1&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case l <- conIn:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(l)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go