我使用以下代码执行命令" npm install" ,现在调试时我发现该命令大约需要10..15秒来执行(取决于我有多少模块)。我想要的是这个命令将在后台执行,程序将继续。
cmd := exec.Command(name ,args...)
cmd.Dir = entryPath
在调试中,我看到要移动到下一行tass大约10..15秒...
我有两个问题:
npm install
之后我需要
做其他事情。答案 0 :(得分:9)
虽然一般来说你需要goroutine来运行并行(或者更确切地说是并发),但是如果以这种方式运行外部命令或应用程序则不需要你使用goroutines(事实上,这是多余的。)
这是因为用于运行命令的exec.Cmd
具有Cmd.Start()
方法,该方法启动指定的命令但不等待它完成。因此,当它在后台运行时你可以自由地做其他事情,当你需要等待它完成(并处理它的结果)时,你可以调用Cmd.Wait()
(它将阻塞并等待命令到完成)。
这就是它的样子:
cmd := exec.Command("npm", "install", "other_params")
cmd.Dir = entryPath
if err := cmd.Start(); err != nil {
log.Printf("Failed to start cmd: %v", err)
return
}
// Do other stuff while cmd runs in background:
log.Println("Doing other stuff...")
// And when you need to wait for the command to finish:
if err := cmd.Wait(); err != nil {
log.Printf("Cmd returned error: %v", err)
}
与Cmd.Start()
相反,如果您不需要在“后台”中运行它,则Cmd.Run()
会启动指定的命令并等待它完成。事实上,Cmd.Run()
只不过是Cmd.Start()
和Cmd.Wait()
来电的链接。
请注意,在“后台”中运行时,为了获取应用的输出,您无法在运行然后命令时调用Cmd.Output()
或Cmd.CombinedOutput()
得到它的输出(你已经启动了命令)。如果需要输出命令,请将缓冲区设置为Cmd.Stdout
,然后可以检查/使用。
这是如何做到的:
cmd := exec.Command("npm", "install", "other_params")
cmd.Dir = entryPath
buf := &bytes.Buffer{}
cmd.Stdout = buf
if err := cmd.Start(); err != nil {
log.Printf("Failed to start cmd: %v", err)
return
}
// Do other stuff while cmd runs in background:
log.Println("Doing other stuff...")
// And when you need to wait for the command to finish:
if err := cmd.Wait(); err != nil {
log.Printf("Cmd returned error: %v", err)
// You may decide to continue or return here...
}
fmt.Println("[OUTPUT:]", buf.String())
如果您还想捕获应用的标准错误流,您可能/必须对Cmd.Stderr
执行相同操作。提示:您可以将相同的缓冲区设置为Cmd.Stdout
和Cmd.Stderr
,然后您将获得组合输出,这可以按照doc进行保证:
如果Stdout和Stderr是同一个作家,并且有一个类型可以与==,
进行比较 一次最多只有一个goroutine会调用Write。
答案 1 :(得分:6)
要并行运行方法,您可以使用goroutines和channels。
在goroutine中,执行exec.Command
操作。这将在后台工作。
您可以使用goroutine中的频道返回信息。
最后,您可以检查通过频道发送的此值。如果您在致电goroutine
后立即检查,它将会阻止,直到从频道收到值。所以你需要在你想要并行完成的其余工作之后检查这个。
type Data struct {
output []byte
error error
}
func runCommand(ch chan<- Data) {
cmd := exec.Command("ls", "-la")
data, err := cmd.CombinedOutput()
ch <- Data{
error: err,
output: data,
}
}
func main() {
c := make(chan Data)
// This will work in background
go runCommand(c)
// Do other things here
// When everything is done, you can check your background process result
res := <-c
if res.error != nil {
fmt.Println("Failed to execute command: ", res.error)
} else {
// You will be here, runCommand has finish successfuly
fmt.Println(string(res.output))
}
}
请参阅操作: Play Ground
现在,对于OP的要求如何从另一个包中实现它。
发表评论:是的,我理解这一点。但是如果我需要从其他包中注册res:=&lt; -c应该如何正确地完成
你可以试试这个: Play Ground 。检查另一个包check
注意:此链接不会构建