如何有效地关闭两个goroutine?
我正在使用两个并发goroutine将stdin/stdout从终端复制到net.Conn目标。出于某种原因,我无法完全停止这两个go例程而不出现紧急错误(因为试图关闭一个关闭的连接)。这是我的代码:如何有效地关闭两个goroutine?,go,Go,我正在使用两个并发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.Wr
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)
}
}
}()
}
func交互(c net.Conn,sessionMap[int]net.Conn){
quit:=make(chan bool)//要退出的频道
复制:=func(r io.ReadCloser,w io.WriteCloser){
延迟函数(){
r、 关闭()
w、 关闭()
关闭(退出)//这就是我试图关闭它的方式
}()
_,err:=io.Copy(w,r)
如果错误!=零{
//
}
}
go func(){
为了{
挑选{
case您不能在一个频道上多次调用close
,没有理由在for循环中调用copy
,因为它只能运行一次,而且您在错误的方向上复制,写入stdin并从stdout读取
简单地询问如何退出2个goroutine很简单,但这不是您在这里需要做的唯一事情。因为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 {
//
}
}
还要注意的是,您可能无法从stdin中断io.Copy
,因此您不能期望interact
函数返回。在函数体中手动执行io.Copy
,并检查每个循环上的半封闭连接可能是一个好主意,这样您就可以更快地中断,并确保完全恢复关闭net.Conn
也可能是这样
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)
}
}
func scanReader(退出chan int,r io.Reader)chan字符串{
行:=制造(成串)
go func(退出chan int){
延迟关闭(行)
扫描:=bufio.NewScanner(r)
对于scan.scan(){
挑选{
如果您两次调用copy
(也不要使用copy
,因为这是一个bultin函数),并且每一个都关闭同一个频道。在关闭之前,您正在检查quit
,因为您在之后调用copy
。您通常不想关闭stdin,也可能不想关闭stdout。为什么在for循环中调用copy
,因为一旦完成,它就完成了?嗨,我不明白,如果您有代码示例没有hey将不胜感激。感谢您的简化,现在就实施它-关于您的后一段:是否愿意给出一个示例代码?我认为这是我上周一直在努力解决的一个问题的核心解决方案!事实上,如果您知道net.Conn
从未期望通过半封闭连接返回数据,将c.Close
放在goroutine中,这就足够了。你的解决方案让我吃惊。多个梯度。我正试图从Stdin error if语句中调用另一个函数(函数B)-if err!=nil{B()}…-不知怎的,一个日志。从函数B打印出来,但是像fmt。Print NOT这样的东西出现了。-知道它为什么会这样吗?@tatoe:嗯,你已经关闭了Stdout,所以你不能再向Stdout写信了。如果你想继续向Stdout写信,那就不要关闭它。这解决了我整整一周的工作。我知道该如何感谢你了!