为了账号安全,请及时绑定邮箱和手机立即绑定

如何高效关闭两个goroutines?

如何高效关闭两个goroutines?

Go
GCT1015 2023-05-22 17:07:36
我正在使用两个并发 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 例程,然后通常继续执行另一个函数。我究竟做错了什么?
查看完整描述

2 回答

?
摇曳的蔷薇

TA贡献1793条经验 获得超6个赞

你不能close多次调用一个通道,没有理由调用copyfor 循环,因为它只能运行一次,而且你正在向错误的方向复制,写入标准输入并从标准输出读取。


简单地询问如何退出 2 个 goroutines 很简单,但这不是您在这里需要做的唯一事情。由于io.Copy是阻塞,您不需要额外的同步来确定调用何时完成。这使您可以显着简化代码,从而更容易推理。


func interact(c net.Conn) {

    go func() {

        // You want to close this outside the goroutine if you

        // expect to send data back over a half-closed connection

        defer c.Close()


        // Optionally close stdout here if you need to signal the

        // end of the stream in a pipeline.

        defer os.Stdout.Close()


        _, err := io.Copy(os.Stdout, c)

        if err != nil {

            //

        }

    }()


    _, err := io.Copy(c, os.Stdin)

    if err != nil {

        //

    }

}

另请注意,您可能无法跳出io.Copyfrom stdin,因此您不能指望函数interact返回。在函数体中手动执行io.Copy并检查每个循环的半关闭连接可能是个好主意,这样您就可以更快地退出并确保完全关闭net.Conn.


查看完整回答
反对 回复 2023-05-22
?
慕运维8079593

TA贡献1876条经验 获得超5个赞

也可以是这样的


 func scanReader(quit chan int, r io.Reader) chan string {

          line := make(chan string)

           go func(quit chan int) {

                    defer close(line)

                    scan := bufio.NewScanner(r)

                    for scan.Scan() {

                    select {

                       case <- quit:

                          return

                       default:

                          s := scan.Text()

                          line <- s

                    }

                    }

                }(quit)

               return line

    }


            stdIn := scanReader(quit, os.Stdin) 

            conIn := scanReader(quit, c) 

        for {

            select {

                    case <-quit:

                        return

                    case l <- stdIn:

                        _, e := fmt.Fprintf(c, l)

                        if e != nil {

                           quit <- 1

                           return

                        }

                    case l <- conIn:

                        fmt.Println(l)

                    }

        }


查看完整回答
反对 回复 2023-05-22
  • 2 回答
  • 0 关注
  • 124 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信