【问题标题】:Creating waiting/busy indicator for executed process为执行的进程创建等待/忙碌指示器
【发布时间】:2018-05-22 11:54:31
【问题描述】:

我有一个像

这样执行子进程的程序
cmd := exec.Command("npm", "install")
log.Printf("Running command and waiting for it to finish...")
err := cmd.Run()
log.Printf("Command finished with error: %v", err)

在运行此命令时,它会下载并安装 npm 包,这需要 10 到 40 秒之间的时间,并且用户在看到标准输出之前不知道会发生什么(10-40 秒取决于网络),但有些东西我可以使用 which 将某些内容打印到 cli 以更清楚地表明发生了什么事情,一些繁忙的指示器(任何类型),直到 stdout 被打印到 cli ?

【问题讨论】:

    标签: go command-line command-line-interface


    【解决方案1】:

    你可以使用另一个 goroutine 定期打印一些东西(比如一个点),比如每秒。当命令完成时,发出该 goroutine 终止的信号。

    类似这样的:

    func indicator(shutdownCh <-chan struct{}) {
        ticker := time.NewTicker(time.Second)
        defer ticker.Stop()
        for {
            select {
            case <-ticker.C:
                fmt.Print(".")
            case <-shutdownCh:
                return
            }
        }
    }
    
    func main() {
        cmd := exec.Command("npm", "install")
        log.Printf("Running command and waiting for it to finish...")
    
        // Start indicator:
        shutdownCh := make(chan struct{})
        go indicator(shutdownCh)
    
        err := cmd.Run()
    
        close(shutdownCh) // Signal indicator() to terminate
    
        fmt.Println()
        log.Printf("Command finished with error: %v", err)
    }
    

    如果您想在每 5 个点后开始一个新行,可以这样做:

    func indicator(shutdownCh <-chan struct{}) {
        ticker := time.NewTicker(time.Second)
        defer ticker.Stop()
        for i := 0; ; {
            select {
            case <-ticker.C:
                fmt.Print(".")
                if i++; i%5 == 0 {
                    fmt.Println()
                }
            case <-shutdownCh:
                return
            }
        }
    }
    

    【讨论】:

    • 谢谢,我会尝试并告诉你:)
    • 问题,如果我使用cmd.start 然后cmd.wait 关闭指标更好?
    • 命令完成时,在这种情况下将在Cmd.Wait()之后。
    • 它一个接一个地工作和创建点,直到它打印出一些东西,有没有办法像. .. .... .. ...一样只打印3个点并重新开始?
    • @RaynD 为此,您需要像termbox-go 这样的第 3 方库。但是,如果有帮助,您也可以在每 3 或 5 个点后打印一个换行符,不需要 3rd 方库。
    【解决方案2】:

    另一种方法是扭转 icza 的答案。由于 npm 命令是一个长时间运行的命令,因此最好使用 goroutine 而不是 ticker(或两者都作为 goroutine),但这是一个偏好问题。

    像这样:

    func npmInstall(done chan struct{}) {
        cmd := exec.Command("npm", "install")
        log.Printf("Running command and waiting for it to finish...")
    
        err := cmd.Run()
        if err != nil {
            log.Printf("\nCommand finished with error: %v", err)
        }
        close(done)
    }
    
    func main() {
        done := make(chan struct{})
        go npmInstall(done)
    
        ticker := time.NewTicker(3 * time.Second)
        defer ticker.Stop()
        for {
            select {
            case <-ticker.C:
                fmt.Print(".")
            case <-done:
                fmt.Println()
                return
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2017-05-25
      • 2018-11-04
      • 2013-11-24
      • 2013-10-26
      • 2014-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多