在 CentOS 上写 Go 并发程序,最容易上手的是 goroutine,但真正影响程序表现的,往往是任务之间怎么通信、什么时候等待退出、参数该怎么调。本文按“并发执行、数据传递、同步控制、示例落地”的顺序整理一遍,读完你可以判断一个并发程序到底缺的是结构设计,还是调优方式。
goroutine:Go 并发模型的起点
在 Go 里,goroutine 是最基础的并发执行单元。它可以理解为由 Go 运行时统一调度的轻量级线程,创建成本低,适合把可以并行处理的任务拆开执行。
创建方式非常直接,只需要在函数调用前加上 go 关键字:
go myFunction()
这一步解决的是“让任务并发跑起来”的问题,但它并不自动解决数据共享和执行顺序问题。也就是说,goroutine 适合负责执行,至于多个任务之间怎么交换数据、怎么保证主程序别过早退出,还要靠后面的机制补齐。
channel:让多个 goroutine 安全传递数据
channel 是 goroutine 之间传递数据的通道,也是 Go 并发模型里很关键的一层。它本质上属于同步原语,目的是让多个并发任务之间的数据交换更可控,减少直接共享内存带来的混乱。
一个基础示例如下:
ch := make(chan int)
go func() {
ch <- 42 // 发送42到通道
}()
value := <-ch // 从通道接收值
这段代码展示了最常见的通信方式:一个 goroutine 负责发送数据,另一个位置负责接收数据。对于实际项目来说,channel 的意义不只是“能传值”,更在于它把并发任务之间的协作关系明确下来。这样做通常比多个 goroutine 直接争抢共享变量更安全,也更容易排查问题。
如果程序里并发任务很多,就要进一步考虑 channel 的使用方式和缓冲区大小。原文提到,这部分没有固定模板,必须结合业务场景和测试结果来调整,否则参数配错后,程序可能不会更快,反而会更卡。
同步原语:控制执行顺序,避免竞态问题
当 goroutine 数量增加后,单靠“能并发执行”还不够,还要解决谁先结束、谁等谁、共享资源是否安全这些问题。Go 标准库里的 sync.WaitGroup、sync.Mutex、sync.RWMutex 就是为这类场景准备的。

其中最常见的是 sync.WaitGroup,适合用来等待一批 goroutine 全部执行完成:
var wg sync.WaitGroup
wg.Add(1) // 增加等待计数
go func() {
defer wg.Done() // 完成时减少计数
}()
wg.Wait() // 等待所有goroutines结束
这类写法的价值很明确:主流程不会因为子任务还没做完就提前退出。对于批量任务、并行请求、异步处理等场景,这是最基础的一层保护。
而像 sync.Mutex、sync.RWMutex 这类工具,则主要用于避免多个 goroutine 同时修改共享数据时出现竞态条件。什么时候该用锁,什么时候更适合改成通过 channel 传值,通常要看程序的数据流设计,而不是简单照搬模板。
CentOS 下的完整并发示例
如果你只是想先把一个最小可运行模型跑起来,下面这个示例已经覆盖了并发执行和同步等待两个核心点:
package main
import (
"fmt"
"sync"
"time"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("Worker %d starting\n", id)
time.Sleep(time.Second)
fmt.Printf("Worker %d done\n", id)
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 5; i++ {
wg.Add(1)
go worker(i, &wg)
}
wg.Wait()
fmt.Println("All workers done")
}
这个程序会启动 5 个 goroutine,每个都执行一次 worker 函数。函数内部先输出开始信息,等待 time.Second,再输出完成信息。主函数通过 sync.WaitGroup 统一等待所有任务结束,最后再打印 All workers done。
这类结构很适合用来验证 CentOS 环境下的 Go 并发运行是否正常,也适合作为后续扩展的起点,比如把 worker 改成处理文件、执行请求或消费任务队列。
如何运行,以及调优时重点看什么
运行方式保持最简单即可。将代码保存为 main.go 后,在 CentOS 终端执行:

go build main.go
./main
如果程序能够正常输出各个 worker 的开始和结束信息,并最终打印 All workers done,说明这套基本并发结构已经工作正常。
接下来真正影响性能的,是并发参数调优。原文特别强调了两类重点:
goroutine 数量不要盲目加
goroutine 很轻量,但不代表越多越好。任务数量、CPU 资源、I/O 等待比例不同,合适的并发数也不同。开得过多,调度开销和资源竞争反而可能把吞吐拉低。
channel 缓冲区大小要结合测试看
channel 的缓冲区大小会直接影响发送和接收的节奏。缓冲太小,可能让生产者频繁阻塞;缓冲太大,也可能掩盖处理速度不匹配的问题,甚至带来额外内存开销。
性能测试是配置依据
无论是调 goroutine 数量,还是改 channel 大小,都不能靠感觉。更稳妥的做法是结合实际业务负载做性能测试,再根据吞吐、延迟和稳定性结果反复调整。对 Go 并发程序来说,参数不是“配上就完事”,而是需要通过测试找到平衡点。
如果把本文内容压缩成一个判断标准,就是:goroutine 负责把任务并发执行起来,channel 负责让任务之间安全通信,sync 工具负责兜住执行顺序和共享资源安全,而最终配置是否合理,必须由性能测试来验证。









