Goroutines don';t线性扩展,但Go程序可以吗?
我正在寻找一些关于性能优化的一般建议 我有一段相当复杂的代码,但是代码存在于一个函数中(没有全局函数),所以我可以a)在多个goroutine中调用这个函数(我的机器上有12个内核)。或者b)使用一次调用的相同类型的函数,编译我的go程序并并行运行整个程序4次 下面是具有相同行为的示例代码:Goroutines don';t线性扩展,但Go程序可以吗?,go,Go,我正在寻找一些关于性能优化的一般建议 我有一段相当复杂的代码,但是代码存在于一个函数中(没有全局函数),所以我可以a)在多个goroutine中调用这个函数(我的机器上有12个内核)。或者b)使用一次调用的相同类型的函数,编译我的go程序并并行运行整个程序4次 下面是具有相同行为的示例代码: package main import ( "fmt" "runtime" "time" ) const size = 140000 type BigStruct struct
package main
import (
"fmt"
"runtime"
"time"
)
const size = 140000
type BigStruct struct {
first []int
second []int
}
func slowFunc() int {
// make local variables
sum := 0
myData := BigStruct{}
myData.first = make([]int, 0, size)
// fill some slices
for i := 0; i < size; i++ {
myData.first = append(myData.first, i)
myData.second = append(myData.second, i)
}
// do pointless calculations
for i := range myData.first {
for j := range
myData.second {
if myData.first[i] == myData.second[j] {
sum++
}
}
}
return sum
}
func slowFuncChan(output chan int) {
// make local variables
sum := 0
myData := BigStruct{}
myData.first = make([]int, 0, size)
// fill some slices
for i := 0; i < size; i++ {
myData.first = append(myData.first, i)
myData.second = append(myData.second, i)
}
// do pointless calculations
for i := range myData.first {
for j := range
myData.second {
if myData.first[i] == myData.second[j] {
sum++
}
}
}
output <- sum
}
func main() {
numCPUs := runtime.NumCPU()
runtime.GOMAXPROCS(numCPUs)
fmt.Println("numCPUs: ", numCPUs)
fmt.Println("Calling slowFunc once...")
start := time.Now()
fmt.Println("sum: ", slowFunc())
t := time.Now() // test
elapsed := t.Sub(start)
fmt.Println("time elapsed: ", elapsed)
fmt.Println()
fmt.Println("Calling slowFunc 4x in goroutines...")
output := make(chan int, 4)
for w := 0; w < 4; w++ {
go slowFuncChan(output)
}
for a := 0; a < 4; a++ {
fmt.Println("sum: ", <-output)
}
t2 := time.Now() // test
elapsed = t2.Sub(t)
fmt.Println("time elapsed: ", elapsed)
}
使用批处理文件,我同时启动程序4次,得到以下4个结果:
numCPUs: 12
Calling slowFunc once...
sum: 140000
time elapsed: 12.7615683s
,
,
,
同时运行4个程序的总时间为12.7705668秒,几乎是goroutines版本(22.4335858秒)的一半
我用8个goroutine和8个同时运行的程序对此进行了测试,得到了相同的结果,多个应用程序运行的goroutine版本是单个goroutine版本的2倍。您如何衡量执行这两个场景的时间?如果您的功能确实不访问共享数据,也没有IO,并且没有启动更多goroutine,4个goroutine应该大致在同一时间内完成。如果不看到代码的其他行为,就不可能进一步帮助您。启动应用程序4次(每次启动1个goroutine)会产生大量开销,性能会更差。@Cerise函数调用大约需要1.5秒,因此我打印了一个简单的时间差。Now()以获得估计值。@DavidNg这也表明,一个应用程序有4个goroutine,性能会更好(一次性加载那个大结构就足够了)。我们应该真正了解您的代码,或者提出一个。添加一个示例。您如何衡量执行这两个场景的时间?如果您的函数确实不访问共享数据,也不执行IO,并且不启动进一步的goroutine,那么4个goroutine应该大致在同一时间内完成。如果不看到代码的其他行为,就不可能进一步帮助您。启动应用程序4次(每次启动1个goroutine)会产生大量开销,性能会更差。@Cerise函数调用大约需要1.5秒,因此我打印了一个简单的时间差。Now()以获得估计值。@DavidNg这也表明,一个应用程序有4个goroutine,性能会更好(一次性加载那个大结构就足够了)。我们真的应该看看你的代码,或者想出一个。添加了一个例子。
numCPUs: 12
Calling slowFunc once...
sum: 140000
time elapsed: 12.7615683s
numCPUs: 12
Calling slowFunc once...
sum: 140000
time elapsed: 12.7705668s
numCPUs: 12
Calling slowFunc once...
sum: 140000
time elapsed: 12.2635664s
numCPUs: 12
Calling slowFunc once...
sum: 140000
time elapsed: 12.1155655s