【问题标题】:Why does the Goroutines take almost identical time as sequential execution?为什么 Goroutines 花费的时间几乎与顺序执行相同?
【发布时间】:2020-07-30 23:15:26
【问题描述】:

我正在调用两个函数,每个函数都带有 Go 例程,我希望同时执行它们所需的时间应该比我一次运行它们要少得多。但我看到完全相反,并行运行它们需要相同或有时 更少 的时间。

Goroutines

    start := time.Now()
    incomeChan := make(chan func() ([]models.Cashflow, *models.ErrorResponse))
    expenseChan := make(chan func() ([]models.Cashflow, *models.ErrorResponse))

    go func(from, to string, cr *fa.Client, c chan<-func() ([]models.Cashflow, *models.ErrorResponse)) {
        log.Println("fetching income")
        c <- func() ([]models.Cashflow, *models.ErrorResponse) { return incomes(from, to, cr)}
        close(c)
    }(from, to, cr, incomeChan)

    go func(from, to string, cr *fa.Client, c chan<-func() ([]models.Cashflow, *models.ErrorResponse)){
        log.Println("fetching expenses")
        c <- func() ([]models.Cashflow, *models.ErrorResponse) {return expenses(from, to, cr)}
        close(c)
    } (from, to, cr, expenseChan)

    income, inErr := (<- incomeChan)()
    if inErr != nil {
        log.Printf("%#v", inErr)
        w.WriteHeader(inErr.Code)
        fmt.Fprint(w, helper.JsonStringify(inErr))
        return
    }
    log.Println("income fetch completed")

    expense, exErr := (<- expenseChan)()
    if exErr != nil {
        log.Printf("%#v", exErr)
        w.WriteHeader(exErr.Code)
        fmt.Fprint(w, helper.JsonStringify(exErr))
        return
    }
    log.Println("expense fetch completed")
    fmt.Printf("%.2fs elapsed\n", time.Since(start).Seconds())

输出

3.33s elapsed
2.79s elapsed
3.37s elapsed

顺序

    income, inErr := incomes(from, to, cr)
    if inErr != nil {
        log.Printf("%#v", inErr)
        w.WriteHeader(inErr.Code)
        fmt.Fprint(w, helper.JsonStringify(inErr))
        return
    }
    
    expense, exErr := expenses(from, to, cr)
    if exErr != nil {
        log.Printf("%#v", exErr)
        w.WriteHeader(exErr.Code)
        fmt.Fprint(w, helper.JsonStringify(exErr))
        return
    }

    fmt.Printf("%.2fs elapsed\n", time.Since(start).Seconds())

输出

2.98s elapsed
3.03s elapsed
2.70s elapsed

是我在这里做错了吗?我期待它花更少的时间在 Goroutine 上。

如果有人知道我在这里可能做错了什么或有任何建议,不胜感激。

【问题讨论】:

标签: go concurrency goroutine


【解决方案1】:

首先,您将并行性与并发性混淆了。 Goroutines 处理并发性,而不是并行性。有关差异的更多背​​景信息,Go 的创建者之一有一个名为 Concurrency is not Parallelism 的演讲。

现在来看一个实际的答案。

您的 goroutines 实际上并不处理任何一个函数的任何处理,而是发送一个调用 expensesincomes 的函数,然后您依次调用它们。这意味着直到您调用 income, inErr := (&lt;- incomeChan)() 时才会计算 incomes() 的实际结果。

基本上,您的“Goroutines”示例在功能上与您的“Sequential”示例相同,但 goroutines 带来了额外的开销,因为它们不能保证立即被调度。

【讨论】:

  • 哦,现在你解释清楚了,谢谢。有什么方法可以在不更改底层代码的情况下使其并发?
  • @PraveenPremaratne 您可以让您的 goroutine 计算值,然后将通道的类型从函数更改为包含 []models.Cashflow, *models.ErrorResponse 作为成员的新结构并相应地处理它们。
  • 嗯,我试图避免这样做。但这可能是最好的解决方案。感谢您的帮助。
  • 仅供参考,在更改之后,现在只需要一半的时间1.52s elapsed
猜你喜欢
  • 2017-02-10
  • 1970-01-01
  • 1970-01-01
  • 2017-08-27
  • 1970-01-01
  • 1970-01-01
  • 2020-03-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多