gpt4 book ai didi

go - 流式命令从 Goroutine 输出进度

转载 作者:IT王子 更新时间:2023-10-29 01:54:49 25 4
gpt4 key购买 nike

Streaming commands output progress问题解决了长时间运行命令的打印进度问题。

我试图将打印代码放在一个 goroutine 中,但扫描器声称已经立即命中 EOF 并且永远不会执行 for block 。

第一次执行 Scan() 方法时执行的 bufio.scan 代码是:

    // We cannot generate a token with what we are holding.
// If we've already hit EOF or an I/O error, we are done.
if s.err != nil {
// Shut it down.
s.start = 0
s.end = 0
return false
}

如果我打印s.err,输出是EOF

我尝试运行的代码是:

cmd := exec.Command("some", "command")
c := make(chan int, 1)

go func(cmd *exec.Cmd, c chan int) {
stdout, _ := cmd.StdoutPipe()

<-c

scanner := bufio.NewScanner(stdout)
for scanner.Scan() {
m := scanner.Text()
fmt.Println(m)
}
}(cmd, c)

cmd.Start()

c <- 1

cmd.Wait()

想法是启动 Goroutine,获取 cmd.stdout,等待 cmd 启动,然后开始处理它的输出。

结果是执行了长命令,程序等待其完成,但没有任何内容打印到终端。

知道为什么第一次调用 scanner.Scan()stdout 已经达到 EOF 了吗?

最佳答案

存在一些问题:

  • 在读取所有数据之前关闭管道。
  • 始终检查错误
  • 开始cmd.Start()c <- struct{}{} 之后并使用无缓冲 channel c := make(chan struct{})

两个工作示例代码:

1:WAITING使用 channel ,然后在 EOF 之后关闭管道使用 defer func() { c <- struct{}{} }() ,就像这个工作示例代码:

package main

import (
"bufio"
"fmt"
"os/exec"
)

func main() {
cmd := exec.Command("Streamer")
c := make(chan struct{})

go run(cmd, c)

c <- struct{}{}
cmd.Start()

<-c
if err := cmd.Wait(); err != nil {
fmt.Println(err)
}
fmt.Println("done.")
}

func run(cmd *exec.Cmd, c chan struct{}) {
defer func() { c <- struct{}{} }()
stdout, err := cmd.StdoutPipe()
if err != nil {
panic(err)
}
<-c
scanner := bufio.NewScanner(stdout)
for scanner.Scan() {
m := scanner.Text()
fmt.Println(m)
}
fmt.Println("EOF")
}

2:您也可以等待使用 sync.WaitGroup ,就像这个工作示例代码:

package main

import (
"bufio"
"fmt"
"os/exec"
"sync"
)

var wg sync.WaitGroup

func main() {
cmd := exec.Command("Streamer")
c := make(chan struct{})
wg.Add(1)
go func(cmd *exec.Cmd, c chan struct{}) {
defer wg.Done()
stdout, err := cmd.StdoutPipe()
if err != nil {
panic(err)
}
<-c
scanner := bufio.NewScanner(stdout)
for scanner.Scan() {
m := scanner.Text()
fmt.Println(m)
}
}(cmd, c)

c <- struct{}{}
cmd.Start()

wg.Wait()
fmt.Println("done.")
}

和 Streamer 示例代码(仅用于测试):

package main

import "fmt"
import "time"

func main() {
for i := 0; i < 10; i++ {
time.Sleep(1 * time.Second)
fmt.Println(i, ":", time.Now().UTC())
}
}

并查看 func (c *Cmd) StdoutPipe() (io.ReadCloser, error)文档:

StdoutPipe returns a pipe that will be connected to the command's standard output when the command starts.

Wait will close the pipe after seeing the command exit, so most callers need not close the pipe themselves; however, an implication is that it is incorrect to call Wait before all reads from the pipe have completed. For the same reason, it is incorrect to call Run when using StdoutPipe. See the example for idiomatic usage.

关于go - 流式命令从 Goroutine 输出进度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38866952/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com