go - 在 Go 中读取命名管道时 100% CPU 使用率

标签 go named-pipes

我有一个简短的 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/

相关文章:

go - 编写模块?

go - Gradle 上的全局变量声明

html - 不允许嵌套函数

c# - CancellationToken 不适用于 WaitForConnectionAsync

bash - 如何使用 bash 冲洗管道

c++ - IPC:在两个程序之间使用 C++ 中的命名管道

去 Coda 2 的语法突出显示?

go - 解码十六进制时间戳,可能是文件时间

无法弄清楚如何在我的客户端-服务器模型中实现线程

c++ - 在 write() 写入的字节数少于请求的字节数后,如何让线程继续?