gpt4 book ai didi

go - channel 和并行混淆

转载 作者:数据小太阳 更新时间:2023-10-29 03:03:30 26 4
gpt4 key购买 nike

我正在自学 Golang,我对并行性及其在 Golang 中的实现方式有些困惑。

给定以下示例:

package main

import (
"fmt"
"sync"
"math/rand"
"time"
)


const (
workers = 1
rand_count = 5000000
)


func start_rand(ch chan int) {
defer close(ch)
var wg sync.WaitGroup
wg.Add(workers)
rand_routine := func(counter int) {
defer wg.Done()
for i:=0;i<counter;i++ {
seed := time.Now().UnixNano()
rand.Seed(seed)
ch<-rand.Intn(5000)

}
}
for i:=0; i<workers; i++ {
go rand_routine(rand_count/workers)
}
wg.Wait()
}

func main() {
start_time := time.Now()
mychan := make(chan int, workers)
go start_rand(mychan)
var wg sync.WaitGroup
wg.Add(workers)

work_handler := func() {
defer wg.Done()
for {
v, isOpen := <-mychan
if !isOpen { break }
fmt.Println(v)
}
}
for i:=0;i<workers;i++ {
go work_handler()
}
wg.Wait()
elapsed_time := time.Since(start_time)
fmt.Println("Done",elapsed_time)
}

这段代码在我的 Macbook 上运行大约需要一分钟。我假设增加“workers”常量会启动额外的 go 例程,并且由于我的笔记本电脑有多个内核,会缩短执行时间。

然而事实并非如此。增加工作人员不会减少执行时间。

我在想,将 workers 设置为 1,将创建 1 个 goroutine 来生成随机数,将其设置为 4,将创建 4 个 goroutine。考虑到我的笔记本电脑的多核特性,我预计 4 个工作人员会在不同的内核上运行,从而提高性能。但是,我发现我所有核心的负载都增加了,即使将 workers 设置为 1 也是如此。我在这里缺少什么?

最佳答案

您的代码存在一些问题,导致它本身就很慢:

  • 您正在循环中播种。这只需要做一次
  • 您使用相同的随机数来源。此源是线程安全的,但会带走并发工作人员的任何性能提升。您可以使用 rand.New
  • 为每个工作人员创建一个源
  • 你打印了很多。打印也是线程安全的。因此,这会带走并发工作人员的任何速度提升。
  • 正如 Zak 已经指出的那样:go 例程中的并发工作成本非常低,而通信成本很高。

你可以像那样重写你的程序。然后,当您更改 worker 数量时,您会看到一些速度提升:

package main

import (
"fmt"
"math/rand"
"time"
)

const (
workers = 1
randCount = 5000000
)

var results = [randCount]int{}

func randRoutine(start, counter int, c chan bool) {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < counter; i++ {
results[start+i] = r.Intn(5000)
}
c <- true
}

func main() {
startTime := time.Now()
c := make(chan bool)

start := 0
for w := 0; w < workers; w++ {
go randRoutine(start, randCount/workers, c)
start += randCount / workers
}

for i := 0; i < workers; i++ {
<-c
}

elapsedTime := time.Since(startTime)
for _, i := range results {
fmt.Println(i)
}
fmt.Println("Time calulating", elapsedTime)

elapsedTime = time.Since(startTime)
fmt.Println("Toal time", elapsedTime)
}

这个程序在一个 go 例程中做了很多工作并且通信最少。每个 go 例程还使用不同的随机源。

关于go - channel 和并行混淆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48944491/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com