如何在Golang中实现合理并行?1.5+版本goroutines是否支持并行?
并行(Parallelism)与并发(Concurrency)的区别,以及Go中Goroutines的并行能力
嘿,咱们先把并行和并发这俩容易搞混的概念掰明白,再聊你关心的Go里goroutines的事儿!
先分清核心区别
- 并发(Concurrency):重点是处理多个任务的能力,这些任务不需要同时运行,而是通过快速切换执行来“看起来同时进行”。比如你一边煮咖啡一边刷消息,同一时刻你其实只在做一件事,但切换速度快,给人一种同时处理的错觉。
- 并行(Parallelism):重点是同时运行多个任务的能力,得有多个独立的执行单元(比如多核CPU的不同核心)同时干活。就像你和室友分工,你煮咖啡他刷消息,真正的“同一时间做不同事”。
Go中Goroutines的并行能力到底咋样?
你提到的GOMAXPROCS确实是关键:
- 在Go 1.5之前,GOMAXPROCS的默认值是1,这意味着Go runtime只会用一个OS线程来调度所有goroutines。哪怕你开了上百个goroutines,它们也只能在这一个线程里交替执行——这时候只有并发,没有并行,因为同一时刻只有一个goroutine在跑。
- 从Go 1.5开始,GOMAXPROCS的默认值改成了机器的CPU核心数。这时候Go runtime可以把goroutines调度到多个OS线程上,而这些线程可以分配到不同的CPU核心上同时运行。
那你问的“自1.5版本起goroutines天生具备并行性”这个结论,不完全准确——应该说:
在多核机器上,当GOMAXPROCS保持默认值(等于核心数)时,goroutines具备了实现并行的条件,但不是所有goroutines的执行都是并行的:
- 如果你的goroutines是计算密集型任务(比如大量数学运算),且数量≥2,Go runtime会把它们调度到不同的核心上,这时候就是真正的并行运行。
- 如果你的goroutines大多是IO阻塞型任务(比如等待网络请求、文件读写),Go runtime会把阻塞的goroutines挂起,调度其他goroutines到线程上,但这时候可能不需要用到多个核心,还是并发的模式。
举个直观的例子
下面是一段计算密集型的代码,在多核机器上运行时,两个goroutines会并行执行,总耗时会接近单个goroutine执行时间的一半:
package main import ( "fmt" "time" ) // 模拟计算密集型任务 func heavyCompute(id int) { fmt.Printf("Goroutine %d 开始执行\n", id) for i := 0; i < 1e8; i++ { // 空循环模拟大量计算 } fmt.Printf("Goroutine %d 执行完成\n", id) } func main() { startTime := time.Now() // 启动两个计算goroutines go heavyCompute(1) go heavyCompute(2) // 等待goroutines完成(实际项目建议用sync.WaitGroup,这里用Sleep简化) time.Sleep(3 * time.Second) elapsed := time.Since(startTime) fmt.Printf("总耗时:%v\n", elapsed) }
如果是在单核机器上运行,两个goroutines会交替执行,总耗时会接近单个goroutine的两倍,这就是纯并发的情况。
内容的提问来源于stack exchange,提问作者Josep
相关产品推荐
相关产品推荐

