CentOS 上 Go 并发编程实践:从基础原语到安全优化

山间有风
山间有风
发布时间:2026-08-24 | 144人浏览过
原创

前言

在 CentOS 上做 Go 并发,先分清每种原语解决的问题:goroutine 负责启动任务,channel 负责传递结果,锁或 atomic 负责保护共享状态,context 负责取消与超时,工作池负责限制并发规模。

在 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 等待结束,避免主程序提前退出。

Go 并发基础原语关系图,展示 goroutine、channel 与互斥锁各自负责的问题
Go 并发基础原语怎么分工把 goroutine、channel 和锁放到同一张关系图里,更容易判断该用哪一种原语。
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 个任务。

Go 工作池与 context 生命周期示意图,展示限流处理与超时取消的配合方式
工作池和 Context 如何配合这一节的重点不是再开更多 goroutine,而是把并发上限和退出时机都控制住。

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 验证。
相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表