duanpenpan5796 2015-01-30 15:08
浏览 87
已采纳

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

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条回答 默认 最新

  • dqpfl2508589 2015-01-30 15:18
    关注

    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.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?