【问题标题】:What am I missing on concurrency?我在并发方面缺少什么?
【发布时间】:2015-11-09 19:38:57
【问题描述】:

我有一个非常简单的脚本,它发出一个 get 请求,然后对响应做一些事情。我有 2 个版本,一个使用 go 例程,一个没有我对两者进行基准测试,速度没有差异。这是我正在做的一个愚蠢的版本:

普通版:

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)
    }
}

去常规:

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 例程时,程序的执行时间会更长。为了有效地使用并发,我缺少什么概念?

【问题讨论】:

  • 我相信因为你在循环中有wg.Wait(),它会阻塞在那里,直到run 在你的“并发”示例中返回含义,它应该表现更差,因为你'添加了等待守卫和 goroutine 开销。我相信这行代码需要是 main 的底部,所以你阻塞直到所有 go 例程完成,而不是在每个例程完成。
  • 另外,你的例子很糟糕,因为你实际上并没有做任何工作。如果这更完整并包括响应处理,那么随着并发请求数量的增加,您可能会看到性能上的重大差异。由于这里唯一真正需要时间的是请求/响应实际上是通过网络传输的,因此不太可能一开始就很好地展示这个概念。
  • @evanmcdonnal gotcha 是的,我简化了这个例子,只是为了展示我是如何调用 go 例程的。我知道 http 也是一个糟糕的基准,因为它有可能导致执行时间变慢的外部因素。更重要的是,我是否正确地调用了您指出的例程,而我不是。谢谢!

标签: go concurrency goroutine


【解决方案1】:

您的示例的主要问题是您在 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() don't wait here cause it serializes execution
    }
    wg.Wait() // wait here, now that all goroutines have been started
}

【讨论】:

    猜你喜欢
    • 2021-05-23
    • 1970-01-01
    • 2011-01-29
    • 1970-01-01
    • 2012-10-01
    • 2010-10-29
    • 2011-03-24
    • 1970-01-01
    相关资源
    最近更新 更多