为什么 Goroutines 花费的时间与顺序执行几乎相同?
Why does the Goroutines take almost identical time as sequential execution?
我正在调用两个函数,每个函数都带有 Go 例程,我希望同时执行它们所花费的时间应该比我 运行 它们一个时少得多一次。但我看到的恰恰相反,它需要相同或有时 更少 的时间来并行 运行 它们。
协程
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 上。
如果有人知道我在这里可能做错了什么或有任何建议,非常感谢。
首先,您混淆了并行性和并发性。 Goroutines 处理并发性,而不是并行性。有关差异的更多背景信息,Go 的创建者之一有一个名为 Concurrency is not Parallelism.
的演讲
现在进入实际答案。
你的 goroutines 实际上并不处理任何一个函数的处理,而是发送一个调用 expenses
和 incomes
的函数,然后你依次调用它们。这意味着在您调用 income, inErr := (<- incomeChan)()
.
之前不会计算 incomes()
的实际结果
本质上,您的“Goroutines”示例在功能上与您的“顺序”示例相同,但是 goroutine 带来了额外的开销,因为它们不能保证立即安排。
我正在调用两个函数,每个函数都带有 Go 例程,我希望同时执行它们所花费的时间应该比我 运行 它们一个时少得多一次。但我看到的恰恰相反,它需要相同或有时 更少 的时间来并行 运行 它们。
协程
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 上。
如果有人知道我在这里可能做错了什么或有任何建议,非常感谢。
首先,您混淆了并行性和并发性。 Goroutines 处理并发性,而不是并行性。有关差异的更多背景信息,Go 的创建者之一有一个名为 Concurrency is not Parallelism.
的演讲现在进入实际答案。
你的 goroutines 实际上并不处理任何一个函数的处理,而是发送一个调用 expenses
和 incomes
的函数,然后你依次调用它们。这意味着在您调用 income, inErr := (<- incomeChan)()
.
incomes()
的实际结果
本质上,您的“Goroutines”示例在功能上与您的“顺序”示例相同,但是 goroutine 带来了额外的开销,因为它们不能保证立即安排。