我有一个简短的 Go 程序,它从命名管道读取数据,并在外部进程写入管道时处理每一行。命名管道是在程序运行之前使用 mkfifo
创建的。
在等待来自命名管道的新行时,该进程占用了 100% 的 CPU,即使它没有进行任何处理也是如此。它在 Ubuntu 14.04 上运行。有什么想法吗?
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
awaitingExit := false
var wg sync.WaitGroup
go func() {
for sig := range c {
awaitingExit = true
// wait for goroutines to finish processing new lines
wg.Wait()
os.Exit(1)
}
}()
file, err := os.OpenFile("file.fifo", os.O_RDONLY, os.ModeNamedPipe)
defer file.Close()
if err != nil {
log.Fatal(err)
}
reader := bufio.NewReader(file)
// infinite loop
for {
line, _, _ := reader.ReadLine()
// stop handling new lines if we're waiting to exit
if !awaitingExit && len(line) > 0 {
wg.Add(1)
go func(uploadLog string) {
defer wg.Done()
handleNewLine(uploadLog)
}(string(line))
}
}
func handleNewLine(line string) {
....
}
最佳答案
你的“无限循环”真的是无限:你永远不会退出或跳出它。
它包含一个if
:
// stop handling new lines if we're waiting to exit
if !awaitingExit && len(line) > 0 {
// code omitted
}
但是如果条件为假,你仍然没有脱离 for
循环,只是继续另一个迭代。一旦你到达 reader
的末尾,这个循环将消耗 100% 的核心,因为在那之后它不会等待任何尝试读取(这将立即返回 EOF)并检查 awaitExit
变量并再次执行这两个步骤。
您需要向 for
循环添加条件以在某个时候退出,或者使用 break
语句来中断它。
改变 for
循环的条件:
for !awaitingExit {
}
用 break
语句更改 for
:
for {
if awaitingExit {
break
}
// code omitted
}
注意:如果 awaitingExit
变量被另一个 goroutine 更改,您需要适当的同步,或者更好的是,使用 channel 作为退出信号。
关于go - 在 Go 中读取命名管道时 100% CPU 使用率,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28238767/