tj *_*wik 5 parallel-processing concurrency background process go
我使用下面的代码,它是"npm install"的执行命令,现在在调试时我看到命令执行大约需要10..15秒(取决于我有多少模块).我想要的是这个命令将在后台执行,程序将继续.
cmd := exec.Command(name ,args...)
cmd.Dir = entryPath
Run Code Online (Sandbox Code Playgroud)
在调试中我看到要移动到下一行tass大约10..15秒...
我有两个问题:
npm install
完成之后,我需要做其他事情.icz*_*cza 10
虽然一般来说你需要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)
}
Run Code Online (Sandbox Code Playgroud)
与此相反,如果您不需要在"后台"中运行它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())
Run Code Online (Sandbox Code Playgroud)
如果您还想捕获应用程序的标准错误流,您可能/必须执行相同操作Cmd.Stderr
.提示:您可以将相同的缓冲区设置为Cmd.Stdout
和Cmd.Stderr
,然后您将获得组合输出,这可以保证按照doc:
如果Stdout和Stderr是同一个编写器,并且具有可以与==进行比较的类型,则
一次最多只有一个goroutine将调用Write.
要并行运行方法,可以使用goroutines和channel.
在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))
}
}
Run Code Online (Sandbox Code Playgroud)
看到实际行动: Play Ground
现在,对于OP的要求如何从另一个包实现它.
发表评论:是的,我理解这一点.但是如果我需要从其他包中注册res:= <-c应该如何正确地完成
你可以试试这个:Play Ground.从另一个包检查check
注意:此链接不会构建
归档时间: |
|
查看次数: |
4000 次 |
最近记录: |