提问人:leetom 提问时间:8/15/2023 更新时间:8/15/2023 访问量:122
如何为循环扫描的 bufio 扫描仪设置超时?
How to set a timeout for a bufio scanner that scans in a loop?
问:
我正在使用 golang 启动一个进程并监控输出。该过程将运行很长时间,我需要能够发送信号来结束它。
我有以下代码,在大多数情况下都能很好地工作。但是,由于某种原因,该进程可能没有输出,并且 for 循环将被方法阻塞并且无法从 接收。Scan()
processFinishChan
有没有一种简单的方法可以为方法设置超时?我尝试了一个在另一个 goroutine 中运行的解决方案,并使用另一个选择从新的 goroutine 和超时通道接收,但考虑到外部循环,会不会有越来越多的 goroutine 被阻止?Scan()
Scan()
for
Scan
// code that start the process...
scanner := bufio.NewScanner(stdout)
for {
select {
case <-processFinishChan: // send to this channel to terminate the process
log.Println("Killing Process")
err := cmdObject.Process.Kill()
if err != nil {
log.Printf("Error Killing: %v", err)
} else {
return
}
default:
// default case, read the output of process and send to user.
if !scanner.Scan() && scanner.Err() == nil {
// reach EOF
return
}
m := scanner.Bytes()
WSOutChanHolder.mu.Lock()
for _, ch := range WSOutChanHolder.data {
ch <- m
}
WSOutChanHolder.mu.Unlock()
}
}
答:
1赞
Dylan Reimerink
8/15/2023
#1
假设是 的结果,读取器应关闭读取器,并在进程退出后等待时中断任何正在进行的读取。stdout
cmdObject.StdoutPipe()
Wait 将在看到命令退出后关闭管道,因此大多数调用者不需要自己关闭管道。
因此,我们需要在单独的 goroutine 中杀死进程,然后在杀死进程后观察它发生并关闭阅读器。Wait
// code that start the process...
scanner := bufio.NewScanner(stdout)
go func() {
<-processFinishChan: // send to this channel to terminate the process
log.Println("Killing Process")
err := cmdObject.Process.Kill()
if err != nil {
log.Printf("Error Killing: %v", err)
}
cmdObject.Wait()
} ()
for {
// default case, read the output of process and send to user.
if !scanner.Scan() && scanner.Err() == nil {
// reach EOF
return
}
m := scanner.Bytes()
WSOutChanHolder.mu.Lock()
for _, ch := range WSOutChanHolder.data {
ch <- m
}
WSOutChanHolder.mu.Unlock()
}
评论
0赞
leetom
8/15/2023
非常感谢,它有效。顺便说一句,我看到了你的答案,但我没有找到 or 的等价物,那么有没有办法实现“阅读 3 秒,如果什么都不读,继续下一行”之类的东西?SetReadDeadline
io.ReadCloser
io.Reader
0赞
Dylan Reimerink
8/15/2023
起初我以为 var 来自 ,但后来意识到它来自一个子进程。返回的是没有此类设施的读取端。管道的写入端安装在 pkg.go.dev/os/exec#Cmd 中。你总是可以实现一个自定义的编写器/管道,这将允许你设置一个上下文,但这需要稍微多一些的工作。stdout
os.Stdout
ReadCloser
io.Pipe
cmd.Stdout
评论
time.After()
Scan