我对goroutines有一些问题。为什么这段代码在~125ms内执行(注意顺序执行):
package main
import (
"os/exec"
"time"
"fmt"
)
func main() {
cmd := exec.Command("lessc", "--yui-compress", "test.less")
n := 2000
start := time.Now()
for i := 0; i < n; i++ {
cmd.Run()
}
finish := time.Now()
fmt.Printf("Program took %v to run\n", finish.Sub(start))
}
当此代码大约需要20秒(使用goroutines并发执行)时:
package main
import (
"os/exec"
"time"
"fmt"
)
func main() {
cmd := exec.Command("lessc", "--yui-compress", "test.less")
ch := make(chan bool)
n := 2000
start := time.Now()
for i := 0; i < n; i++ {
go lessc(ch, cmd)
}
fmt.Println(n, " goroutines started.")
for i := 0; i < n; i++ {
_ = <-ch
}
finish := time.Now()
fmt.Printf("Program took %v to run\n", finish.Sub(start))
}
func lessc(ch chan bool, c *exec.Cmd) {
c.Run()
ch <- true
}
在i7 720QM(4C / 8T)8GB RAM linux / x86-64上使用go 1.0.3 还使用1.0.2构建和测试,并在同一台机器上遇到同样的问题。
编辑:由@jnml解决。如果有人关心这里新的固定并发代码,那就是:
package main
import (
"os/exec"
"time"
"fmt"
)
func main() {
ch := make(chan bool)
n := 2000
start := time.Now()
for i := 0; i < n; i++ {
go lessc(ch)
}
fmt.Println(n, " goroutines started.")
for i := 0; i < n; i++ {
_ = <-ch
}
finish := time.Now()
fmt.Printf("Program took %v to run\n", finish.Sub(start))
}
func lessc(ch chan bool) {
cmd := exec.Command("lessc", "--yui-compress", "test.less")
cmd.Run()
ch <- true
}
答案 0 :(得分:11)
IMO您的程序不正确。它包含竞争条件,因此可以做任何事情。任何时机都没有意义。
您正在创建一个 exec.Cmd
,然后同时(==数据竞争)从多个goroutines执行其Run
方法。 exec.Cmd
从未提及它可以多次重复使用Run
- 即使是连续的。
exec.Cmd
有一些状态由exec.Command
初始化,执行Run
后状态不同。 IOW,执行Run
方法后,状态不再被初始化,可能不适合另一个Run