goroutines造成重大减速和头痛

时间:2013-04-17 10:20:39

标签: concurrency go goroutine

我对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
}

1 个答案:

答案 0 :(得分:11)

IMO您的程序不正确。它包含竞争条件,因此可以做任何事情。任何时机都没有意义。

您正在创建一个 exec.Cmd,然后同时(==数据竞争)从多个goroutines执行其Run方法。 exec.Cmd从未提及它可以多次重复使用Run - 即使是连续的。

exec.Cmd有一些状态由exec.Command初始化,执行Run后状态不同。 IOW,执行Run方法后,状态不再被初始化,可能不适合另一个Run