Go语言在Debian中的并发编程实践
Go语言以“原生并发”为核心特性,其并发模型基于CSP(通信顺序进程)理论,通过goroutines(轻量级线程)、**channels(通信机制)和sync包(同步工具)**实现高效的并发编程。在Debian系统中,由于Go语言的良好兼容性(支持Linux内核),开发者可借助系统环境快速实现并发程序。以下是具体实践要点:
Goroutines是Go语言并发的基石,由Go运行时管理,开销极小(初始栈仅几KB,可动态扩容),可在单个进程中创建成千上万个。使用go关键字即可启动:
func printNumbers() {
for i := 1; i <= 5; i++ {
fmt.Printf("Number: %d\n", i)
time.Sleep(500 * time.Millisecond)
}
}
func main() {
go printNumbers() // 启动goroutine
fmt.Println("Main function continues...")
time.Sleep(3 * time.Second) // 等待goroutine完成(实际项目中应使用同步机制)
}
注意:避免在goroutine中执行无限制的阻塞操作(如无限循环无sleep),否则可能导致资源耗尽。
Channels是goroutines之间同步与通信的首选方式,遵循“通过通信共享内存”而非“通过共享内存通信”的原则,可有效避免数据竞争。
func worker(done chan bool) {
fmt.Println("Working...")
time.Sleep(time.Second)
fmt.Println("Done")
done <- true
}
func main() {
done := make(chan bool)
go worker(done)
<-done // 主goroutine阻塞,直到收到worker的信号
}
func producer(ch chan int) {
for i := 1; i <= 5; i++ {
ch <- i // 发送数据到缓冲通道
fmt.Printf("Produced: %d\n", i)
}
close(ch) // 关闭通道(通知接收方无更多数据)
}
func consumer(ch chan int) {
for num := range ch { // 从通道接收数据(直到通道关闭)
fmt.Printf("Consumed: %d\n", num)
}
}
func main() {
ch := make(chan int, 3) // 缓冲大小为3
go producer(ch)
consumer(ch)
}
关键实践:优先使用带缓冲通道提高吞吐量,但需根据场景调整缓冲大小(避免过大导致内存浪费)。
当需要保护共享资源(如全局变量、文件句柄)时,需使用sync包中的同步原语:
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done() // goroutine结束时调用(计数器-1)
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 <= 3; i++ {
wg.Add(1) // 启动前增加计数器(+1)
go worker(i, &wg)
}
wg.Wait() // 阻塞直到计数器归零
fmt.Println("All workers completed")
}
var (
counter int
mu sync.Mutex // 互斥锁
)
func increment() {
mu.Lock() // 加锁
counter++ // 修改共享变量
mu.Unlock() // 解锁
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
increment()
}()
}
wg.Wait()
fmt.Println("Final Counter:", counter) // 输出1000(无竞争)
}
var (
instance *MyStruct
once sync.Once
)
func GetInstance() *MyStruct {
once.Do(func() {
instance = &MyStruct{} // 仅执行一次
})
return instance
}
注意:避免过度同步(如锁的粒度过大),尽量缩小临界区范围。
func worker(id int, jobs <-chan int, results chan<- int) {
for job := range jobs {
fmt.Printf("Worker %d processing job %d\n", id, job)
time.Sleep(time.Second)
results <- job * 2 // 返回结果
}
}
func main() {
jobs := make(chan int, 10)
results := make(chan int, 10)
// 启动3个worker
for w := 1; w <= 3; w++ {
go worker(w, jobs, results)
}
// 发送5个任务
for j := 1; j <= 5; j++ {
jobs <- j
}
close(jobs) // 关闭任务通道
// 收集结果
for a := 1; a <= 5; a++ {
fmt.Println("Result:", <-results)
}
}
func longTask(ctx context.Context) {
select {
case <-time.After(5 * time.Second):
fmt.Println("Task completed")
case <-ctx.Done(): // 接收取消信号
fmt.Println("Task cancelled:", ctx.Err())
}
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel() // 释放资源
go longTask(ctx)
time.Sleep(3 * time.Second) // 等待任务结束
}
输出:“Task cancelled: context deadline exceeded”(任务在2秒后被取消)。go build -race开启race detector检测数据竞争(如未同步的共享变量访问)。close(channel)关闭通道(通知接收方停止等待),使用sync.WaitGroup等待所有goroutine完成。sudo apt update && sudo apt install golang-go),或从官网下载二进制包部署。GOMAXPROCS设置并行执行的CPU核心数(默认为CPU逻辑核心数,可通过runtime.GOMAXPROCS(n)调整),提升并发性能。go mod初始化项目(go mod init project-name),管理第三方依赖(如go get github.com/some/package)。