并发编程方面我错过了什么?

huangapple go评论74阅读模式
英文:

What am I missing on concurrency?

问题

我有一个非常简单的脚本,它发送一个GET请求,然后对响应进行一些处理。我有两个版本,一个使用go routine,一个不使用。我对它们进行了基准测试,速度上没有任何差异。以下是我正在做的简化版本:

普通版本:

func main() {
    url := "http://finance.yahoo.com/q?s=aapl"

    for i := 0; i < 250; i++ {
        resp, err := http.Get(url)
        if err != nil {
            fmt.Println(err)
        }

        fmt.Println(resp.Status)
    }
}

Go Routine版本:

func main() {
    url := "http://finance.yahoo.com/q?s=aapl"

    for i := 0; i < 250; i++ {
        wg.Add(1)
        go run(url, &wg)
        wg.Wait()
    }
}

func run(url string, wg *sync.WaitGroup) {
    defer wg.Done()
    resp, err := http.Get(url)
    if err != nil {
        fmt.Println(err)
    }

    fmt.Println(resp.Status)
}

在大多数情况下,当我使用go routine时,程序执行的时间更长。我错过了哪个概念,无法有效地使用并发?

英文:

I have a very simple script that makes a get request and then does some thing with the response. I have 2 version one using a go routine and one without I bencharmaked both and there was no difference in speed. Here is a dumb down version of what I'm doing:

Regular Version:

func main() {
	url := &quot;http://finance.yahoo.com/q?s=aapl&quot;

	for i := 0; i &lt; 250; i++ {
		resp, err := http.Get(url)
		if err != nil {
			fmt.Println(err)
		}

		fmt.Println(resp.Status)
	}
}

Go Routine:

func main() {
	url := &quot;http://finance.yahoo.com/q?s=aapl&quot;

	for i := 0; i &lt; 250; i++ {
		wg.Add(1)
		go run(url, &amp;wg)
		wg.Wait()
	}
}

func run(url string, wg *sync.WaitGroup) {
	defer wg.Done()
	resp, err := http.Get(url)
	if err != nil {
		fmt.Println(err)
	}

	fmt.Println(resp.Status)
}

In most cases when I used a go routine the program took longer to execute. What concept am I missing to understand using concurrency efficiently?

答案1

得分: 4

你的示例代码的主要问题是在for循环中调用了wg.Wait()。这会导致执行被阻塞,直到在run函数中的延迟调用wg.Done()。结果是,执行不是并发的,它在一个goroutine中发生,但在启动goroutine i之后和启动i+1之前被阻塞。如果你将该语句放在循环之后,像下面这样,那么你的代码在循环之后不会被阻塞(所有的goroutine都已经启动,有些可能已经完成)。

func main() {
    url := "http://finance.yahoo.com/q?s=aapl"

    for i := 0; i < 250; i++ {
        wg.Add(1)
        go run(url, &wg)
        // wg.Wait() 不要在这里等待,因为它会串行化执行
    }
    wg.Wait() // 在这里等待,现在所有的goroutine都已经启动
}
英文:

The main problem with your example is that you're calling wg.Wait() within the for loop. This causes execution to block until you the deferred wg.Done() call inside of run. As a result, the execution isn't concurrent, it happens in a goroutine but you block after starting goroutine i and before starting i+1. If you place that statement after the loop instead like below then your code won't block until after the loop (all goroutines have been started, some may have already completed).

func main() {
    url := &quot;http://finance.yahoo.com/q?s=aapl&quot;

    for i := 0; i &lt; 250; i++ {
        wg.Add(1)
        go run(url, &amp;wg)
        // wg.Wait() don&#39;t wait here cause it serializes execution
    }
    wg.Wait() // wait here, now that all goroutines have been started
}

huangapple
  • 本文由 发表于 2015年11月10日 03:38:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/33616864.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定