如何关闭等待 I/O 的 goroutine

我创建了两个 go 例程sender和receiver,sender 将不断从用户(键盘)获取数据并写入流,receiver 将独立地从流中获取值将其打印到屏幕上。两者都使用 goroutine 并发


在某个时间点接收器失败并关闭连接并退出接收器 go 例程,但等待用户输入(i/o 操作)的发送器 go 例程不会关闭。这种场景下如何退出所有的goroutine?


下面是此场景的示例代码。


package main


import (

    "fmt"

    "time"

)


var stop bool = false


func sender() {

    str := ""

    for !stop {

        fmt.Scanf("%s", &str)

        fmt.Println("Entered :", str)

    }   

    fmt.Println("Closing sender goroutine")

}


func receiver() {

    i := 0

    for !stop {

        i++

        if i > 5 { 

            stop = true

        }

        time.Sleep(1 * time.Second)

    }   

    fmt.Println("Closing receiver goroutine")

}


func main() {

    go sender()

    go receiver()


    /* Wait for goroutines to finish */

    for !stop {

        time.Sleep(1 * time.Millisecond)

    }   

    time.Sleep(1 * time.Second)


    panic("Display stack")

}

上面的代码发送者将在 5 个循环接收者退出接收者程序后等待用户输入。 I expect when receiver close, go routine which waiting on i/o has to be closed.


请帮助我解决这个问题。


桃花长相依
浏览 229回答 2
2回答

素胚勾勒不出你

正如 Dave C 和 JimB 所说,使用通道来协调 goroutine。这是一个可能会有所帮助的示例。收到用户的5条消息后退出:package mainimport "fmt"var pipe = make(chan string) //shares text entered by uservar stop = make(chan bool)&nbsp; &nbsp;//shares stop signalfunc listen() {&nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; var input string&nbsp; &nbsp; &nbsp; &nbsp; fmt.Scan(&input)&nbsp; &nbsp; &nbsp; &nbsp; pipe <- input&nbsp; &nbsp; }}func write() {&nbsp; &nbsp; for i := 0; i < 5; i++ {&nbsp; &nbsp; &nbsp; &nbsp; var output string&nbsp; &nbsp; &nbsp; &nbsp; output = <-pipe&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Received", output)&nbsp; &nbsp; }&nbsp; &nbsp; stop <- true}func main() {&nbsp; &nbsp; go listen()&nbsp; &nbsp; go write()&nbsp; &nbsp; <-stop}

阿波罗的战车

首先,您的代码有一个围绕stop变量的竞赛。当发生数据竞争时,无法保证您的程序会按照定义的那样运行。使用通道来同步 goroutine。然而,这不是您继续编程的原因。您的代码在 上阻塞fmt.Scanf,无法检查stop条件。由于无法中断 Stdin 上的读取(发生在 内部fmt.Scanf),因此您需要在Scanf再次调用之前检查停止条件。如果没有更多输入,但您在 Stdin 上有一个待处理的 Read,处理它的最简单方法是让 goroutine 运行。有一些相当复杂的方法可以使用称为“自管道”的技巧来解决这个问题,但通常不值得付出努力,因为 goroutine 很小并且不占用太多资源。for !stop {&nbsp; &nbsp; fmt.Scanf("%s", &str)&nbsp; &nbsp; fmt.Println("Entered :", str)&nbsp; &nbsp; // use a channel to detect when to exit&nbsp; &nbsp; select {&nbsp; &nbsp; case <-stop:&nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; default:&nbsp; &nbsp; }}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go