Golang中是否会以某种方式修改goroutines?
Golang中是否会以某种方式修改goroutines? 我曾遇到过一些程序,由于某些全局变量的访问,使用多个goroutine拆分问题反而比使用单个goroutine运行得更慢。当移除这些访问后,程序变得比单goroutine版本快得多,这符合预期。
那么,Go是否会对作为goroutine运行的代码做任何处理……比如在它认为可能存在竞争问题的地方自动添加互斥锁?如果没有,那么如何解释那种情况下的性能下降呢?
谢谢
当所有goroutine访问同一个变量时,缓存失效可能会产生影响。
更多关于Golang中是否会以某种方式修改goroutines?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
你好 Telo,
这并不能解释它,因为在示例中,全局变量是一个整数,用于累加计数。goroutine 正在更新这个计数。当我移除那个全局变量的更新后,速度就加快了。
我得尝试重新创建那个具体的示例——那是一个曼德博集合生成器。
Jon
Go 不会自动添加“互斥锁”,因为它无法读取程序员的思维来决定程序应该做什么。
一个可能的解释是垃圾回收。全局变量始终位于堆上,因此每个垃圾回收周期(在 Go 中,这是持续进行的,不会冻结你的程序)都会因为该变量而需要多做一点工作。单个全局变量本身没什么,但如果它有许多指向其他变量的指针字段,垃圾回收器将需要扫描每一个指针。
func main() {
fmt.Println("hello world")
}
在Go语言中,运行时不会自动为goroutine添加互斥锁或同步原语。性能下降通常是由于共享资源的竞争和调度开销导致的。以下是一个示例,说明全局变量访问如何影响性能:
package main
import (
"fmt"
"sync"
"time"
)
var globalCounter int
var mu sync.Mutex
func withoutMutex() {
for i := 0; i < 1000000; i++ {
globalCounter++
}
}
func withMutex() {
for i := 0; i < 1000000; i++ {
mu.Lock()
globalCounter++
mu.Unlock()
}
}
func main() {
// 测试无锁版本
start := time.Now()
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
withoutMutex()
}()
}
wg.Wait()
fmt.Printf("无锁版本耗时: %v, 结果: %d\n", time.Since(start), globalCounter)
// 重置计数器
globalCounter = 0
// 测试有锁版本
start = time.Now()
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
withMutex()
}()
}
wg.Wait()
fmt.Printf("有锁版本耗时: %v, 结果: %d\n", time.Since(start), globalCounter)
}
输出可能类似:
无锁版本耗时: 12.456ms, 结果: 4567892
有锁版本耗时: 345.678ms, 结果: 10000000
性能下降的原因:
- 缓存一致性开销:多个goroutine修改同一变量导致CPU缓存频繁失效
- 内存争用:对共享内存的并发访问需要串行化
- 调度器压力:大量goroutine竞争资源会增加调度延迟
解决方案示例:
// 使用局部变量减少竞争
func optimized() {
local := 0
for i := 0; i < 1000000; i++ {
local++
}
mu.Lock()
globalCounter += local
mu.Unlock()
}
// 使用通道
func channelSolution() {
ch := make(chan int, 10)
for i := 0; i < 10; i++ {
go func(id int) {
sum := 0
for j := 0; j < 1000000; j++ {
sum++
}
ch <- sum
}(i)
}
total := 0
for i := 0; i < 10; i++ {
total += <-ch
}
fmt.Println("通道方案结果:", total)
}
使用go run -race可以检测数据竞争:
go run -race main.go
性能下降的根本原因是共享状态的管理开销,而非Go运行时的自动干预。

