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

时间:2015-01-30 15:08:27

标签: 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) {
    ....
}

1 个答案:

答案 0 :(得分:1)

你的"无限循环"真的是无限:你永远不会退出它或跳出它。

它包含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 {
}

使用for声明更改break

for {
    if awaitingExit {
        break
    }
    // code omitted
}

注意:如果awaitingExit变量被另一个goroutine更改,则需要正确同步,或者更好的是,使用通道进行退出信令。