我在并发方面缺少什么?
What am I missing on concurrency?
我有一个非常简单的脚本,它发出一个获取请求,然后对响应做一些事情。我有 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 routine 时,程序需要更长的时间来执行。我缺少什么概念来理解有效地使用并发?
您的示例的主要问题是您在 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
}
我有一个非常简单的脚本,它发出一个获取请求,然后对响应做一些事情。我有 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 routine 时,程序需要更长的时间来执行。我缺少什么概念来理解有效地使用并发?
您的示例的主要问题是您在 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
}