在 CentOS 上写 Go 并发程序,重点是任务收口、结果传递和共享状态同步。
先把 CentOS 上的 Go 环境装好
安装 go1.20.4.linux-amd64.tar.gz:
wget https://golang.org/dl/go1.20.4.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.20.4.linux-amd64.tar.gz
echo "export PATH=$PATH:/usr/local/go/bin" >> ~/.bashrc
source ~/.bashrc
go version
goroutine、channel 和锁分别解决什么问题
goroutine
goroutine 由运行时调度,初始内存约 2KB。关键是用 sync.WaitGroup 等待结束,避免主程序提前退出。

package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
fmt.Printf("Goroutine %d executed\n", id)
}(i)
}
wg.Wait()
}
channel
goroutine 间传结果,优先用 channel。带缓冲 channel 适合统一收集结果:
package main
import (
"fmt"
"net/http"
)
func download(url string, ch chan<- string) {
resp, err := http.Get(url)
if err != nil {
ch <- fmt.Sprintf("Error downloading %s: %v", url, err)
return
}
defer resp.Body.Close()
ch <- fmt.Sprintf("Downloaded %s (Status: %s)", url, resp.Status)
}
func main() {
urls := []string{"https://example.com/file1", "https://example.com/file2"}
ch := make(chan string, len(urls))
for _, url := range urls {
go download(url, ch)
}
for i := 0; i < len(urls); i++ {
fmt.Println(<-ch)
}
}
锁
多个 goroutine 修改共享状态时,用 Mutex;只做加减时可考虑 atomic。
package main
import (
"fmt"
"sync"
)
var (
counter int
mu sync.Mutex
)
func increment() {
mu.Lock()
counter++
mu.Unlock()
}
两种更常用的进阶并发模式
工作池
并发不是越多越好。工作池用 worker 数量限制并发,原文示例为 3 个 worker 处理 5 个任务。

context
context 传递取消和超时,避免 goroutine 泄漏:
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
并发安全检查与性能优化怎么做
竞态检测:
go run -race main.go
go test -race ./...
原子计数:
atomic.AddInt32(&counter, 1)
fmt.Println("Counter:", atomic.LoadInt32(&counter))
还要检查 channel 收发是否匹配,context 是否沿调用链继续传递。
落地时可以遵循的几条经验
- 任务启动用 goroutine。
- 结果传递优先用 channel。
- 共享状态用锁或 atomic。
- 生命周期交给 context。
- 用工作池限制 CPU 密集型并发。
- 结合
GOMAXPROCS和-race验证。













