Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stopping a bufio.Scanner with a stop channel

Tags:

go

I'm writing something that reads lines from os.Stdin using a bufio.Scanner like:

for s.scanner.Scan() {
  line := s.scanner.Text()
  // process line
}

This is running in a goroutine and I want to be able to stop it when a chan struct{} closes. However as Scan blocks until there is another line, I'm at a loss as how to stop it, if there is no more input, it'll block indefinitely.

Can anyone point me in the right direction here?

like image 499
Michael Baldry Avatar asked Oct 16 '22 04:10

Michael Baldry


1 Answers

By creating one more indirection and ignoring the underlying, we can stop.

// actual reading, converts input stream to a channel
func readUnderlying(lines chan interface{}) {
    s := bufio.NewScanner(os.Stdin)
    for s.Scan() {
        lines <- s.Text()
    }
    lines <- s.Err()
}

func read(stop chan struct{}) {
    input := make(chan interface{}) // input stream
    go readUnderlying(input) // go and read
    for {
        select { // read or close
        case lineOrErr := <-input:
            fmt.Println(lineOrErr)
        case <-stop:
            return
        }
    }
}

func main() {
    stop := make(chan struct{})
    go read(stop)

    // wait some to simulate blocking
    time.Sleep(time.Second * 20) // it will print what is given
    close(stop)
    time.Sleep(time.Second * 20) // stopped so no more processing
}
like image 119
ferhat Avatar answered Oct 21 '22 04:10

ferhat