如何在不使用频道阻塞的情况下使用代码报告统计信息?

How to report stats with ticker without blocking using channel?

我想在读取大文件时每 N 秒报告一次各种统计数据。我找到了自动收报机和频道,但无法弄清楚如何在后台继续读取文件时使其非阻塞。我也尝试制作字符串通道并使用 select{ case: <-msg} 但程序崩溃然后死锁。什么是正确的方法?

稍后我可能会添加差异,以便所需的速度和时间也可以包含在定期报告中。

package main

import (
    "log"
    "os"
    "fmt"
    "bufio"
    "strings"
    "time"
)

func main() {
    filename := "large-file.dat"

    log.Printf("Opening file: '%v'", filename)
    file, err := os.Open(filename)
    if err != nil {
        fmt.Fprintf(os.Stderr, "File error: %v", err)
        os.Exit(1)
    }

    sourceTotalSizeBytes := uint64(0)
    sourceReadedBytes := uint64(0)

    if finfo, err := file.Stat(); err == nil {
        sourceTotalSizeBytes = uint64(finfo.Size())
        log.Printf("Size: %v bytes", sourceTotalSizeBytes)
    }

    scanner := bufio.NewScanner(file)

    // Output stats every n seconds
    ticker := time.NewTicker(time.Second * 2)
    defer ticker.Stop()

    for scanner.Scan() {
        lineReader := strings.NewReader(scanner.Text())
        sourceReadedBytes += uint64(lineReader.Size())

        // Report stats every n seconds
        <-ticker.C
        go func() {
            percent := ( float64(sourceReadedBytes) * float64(100) ) / float64(sourceTotalSizeBytes)
            log.Printf("%v / %v %v%%", sourceReadedBytes, sourceTotalSizeBytes, percent)
        }()

        // Simulate work being done to line
        time.Sleep(time.Millisecond * 10)

    }

    file.Close()
}

默认使用select以避免在自动收报机上阻塞。从自动收报机接收到值时记录:

select {
case <-ticker.C:
    percent := ( float64(sourceReadedBytes) * float64(100) ) / float64(sourceTotalSizeBytes)
    og.Printf("%v / %v %v%%", sourceReadedBytes, sourceTotalSizeBytes, percent)
default:
    // do nothing
}