英文:
100% CPU usage when reading named pipe in Go
问题
我有一个简短的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
// 等待goroutine完成对新行的处理
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)
// 无限循环
for {
line, _, _ := reader.ReadLine()
// 如果正在等待退出,则停止处理新行
if !awaitingExit && len(line) > 0 {
wg.Add(1)
go func(uploadLog string) {
defer wg.Done()
handleNewLine(uploadLog)
}(string(line))
}
}
func handleNewLine(line string) {
// 处理新行的代码
....
}
这是你要翻译的内容。
英文:
I have a short Go program which reads from a named pipe and processes each line as an external process writes to the pipe. The named pipe is created before the program runs using mkfifo
.
The process is taking up 100% of the CPU when waiting for a new line from the named pipe, even when it's not doing any processing. It's running on Ubuntu 14.04. Any ideas?
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) {
....
}
答案1
得分: 1
你的“无限循环”真的是“无限”的:你从未退出或跳出它。
它包含一个if
语句:
// 如果我们正在等待退出,则停止处理新行
if !awaitingExit && len(line) > 0 {
// 代码省略
}
但是,如果条件为假,你仍然没有跳出for
循环,只是继续下一次迭代。一旦到达reader
的末尾,这个循环将占用100%的核心,因为在那之后它将不会等待任何东西,只是尝试读取(立即返回EOF)并检查awaitExit
变量,然后再次执行这两个步骤。
你需要在for
循环中添加条件以便在某个时刻退出,或者使用break
语句跳出循环。
带有条件的修改后的for
循环:
for !awaitingExit {
}
带有break
语句的修改后的for
循环:
for {
if awaitingExit {
break
}
// 代码省略
}
注意:如果awaitingExit
变量由另一个goroutine更改,你需要适当的同步,或者更好地使用通道进行退出信号传递。
英文:
Your "infinite loop" is really infinite: you never exit it or jump out of it.
It contains an if
:
// stop handling new lines if we're waiting to exit
if !awaitingExit && len(line) > 0 {
// code omitted
}
But if the condition is false, you're still not getting out of the for
loop, just continue with another iteration. Once you reach the end of reader
, this loop will consume 100% of a core because after that it will not wait for anything just trying to read (which will immediately return EOF) and checking the awaitExit
variable and doing these 2 steps again.
You either need to add condition to the for
loop to exit sometime, or use a break
statement to break out of it.
Altered for
loop with a condition:
for !awaitingExit {
}
Altered for
with a break
statement:
for {
if awaitingExit {
break
}
// code omitted
}
Note: if awaitingExit
variable is changed by another goroutine, you need proper synchronization, or better, use channels for exit signalling.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论