本教程将指导你在Debian系统上使用Golang实现并发编程,涵盖环境准备、基础并发原语(goroutines、channels)、同步工具(sync.WaitGroup、sync.Mutex)及常见并发模式(worker pool、pipeline)。
在Debian上安装Golang需通过包管理器完成,步骤如下:
# 更新软件包索引
sudo apt update
# 安装Golang(默认版本为最新稳定版)
sudo apt install golang-go
# 验证安装(显示版本号即成功)
go version
Goroutines是Go的核心并发单元,使用go关键字启动,无需手动管理生命周期。示例如下:
package main
import (
"fmt"
"time"
)
func printNumbers() {
for i := 1; i <= 5; i++ {
fmt.Printf("Number: %d\n", i)
time.Sleep(1 * time.Second) // 模拟耗时操作
}
}
func main() {
go printNumbers() // 启动goroutine
// 主goroutine继续执行
for i := 1; i <= 5; i++ {
fmt.Printf("Main: %d\n", i)
time.Sleep(1 * time.Second)
}
}
说明:主goroutine与printNumbers goroutine并发执行,输出交替出现。
Channels用于goroutines之间的数据传递,避免共享内存的竞态条件。示例如下:
package main
import "fmt"
func worker(ch chan<- int) {
for i := 1; i <= 5; i++ {
ch <- i // 发送数据到channel
}
close(ch) // 关闭channel(通知接收方无更多数据)
}
func main() {
ch := make(chan int) // 创建无缓冲channel
go worker(ch) // 启动worker goroutine
// 从channel接收数据(阻塞直到有数据)
for num := range ch {
fmt.Printf("Received: %d\n", num)
}
}
说明:ch := make(chan int)创建无缓冲channel,close(ch)关闭channel,for num := range ch循环接收数据直到channel关闭。
sync.WaitGroup用于等待多个goroutines执行完毕,避免主goroutine提前退出。示例如下:
package main
import (
"fmt"
"sync"
"time"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done() // 函数结束时通知WaitGroup
fmt.Printf("Worker %d started\n", id)
time.Sleep(2 * time.Second) // 模拟耗时操作
fmt.Printf("Worker %d finished\n", id)
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 3; i++ {
wg.Add(1) // 增加WaitGroup计数器
go worker(i, &wg) // 启动goroutine(传入WaitGroup指针)
}
wg.Wait() // 阻塞直到计数器归零
fmt.Println("All workers finished")
}
说明:wg.Add(1)增加计数器,defer wg.Done()确保函数结束时计数器减1,wg.Wait()阻塞主goroutine直到计数器归零。
sync.Mutex用于保护共享资源,防止多个goroutines同时修改导致的数据不一致。示例如下:
package main
import (
"fmt"
"sync"
)
var (
counter int
mutex sync.Mutex // 定义互斥锁
)
func increment() {
mutex.Lock() // 加锁(阻塞直到获取锁)
counter++ // 修改共享变量
mutex.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.Printf("Final counter: %d\n", counter) // 输出: 1000
}
说明:mutex.Lock()和mutex.Unlock()包裹共享变量的修改操作,确保同一时刻只有一个goroutine能访问。
Worker Pool模式通过固定数量的goroutines处理任务,避免资源耗尽。示例如下:
package main
import (
"fmt"
"sync"
)
func worker(id int, jobs <-chan int, results chan<- int, wg *sync.WaitGroup) {
defer wg.Done()
for job := range jobs {
fmt.Printf("Worker %d processing job %d\n", id, job)
results <- job * 2 // 处理结果发送到results channel
}
}
func main() {
const numJobs = 5
const numWorkers = 3
jobs := make(chan int, numJobs)
results := make(chan int, numJobs)
var wg sync.WaitGroup
// 启动worker goroutines
for w := 1; w <= numWorkers; w++ {
wg.Add(1)
go worker(w, jobs, results, &wg)
}
// 发送任务到jobs channel
for j := 1; j <= numJobs; j++ {
jobs <- j
}
close(jobs) // 关闭jobs channel(通知worker无更多任务)
wg.Wait() // 等待所有worker完成
close(results) // 关闭results channel
// 打印处理结果
for result := range results {
fmt.Printf("Result: %d\n", result)
}
}
说明:numWorkers控制并发数量,jobs channel分发任务,results channel收集结果。
Pipeline模式将多个处理步骤串联,每个步骤由独立的goroutine完成,前一步的输出作为下一步的输入。示例如下:
package main
import "fmt"
// generate生成0~9的整数
func generate() <-chan int {
ch := make(chan int)
go func() {
for i := 0; i < 10; i++ {
ch <- i
}
close(ch)
}()
return ch
}
// square计算输入整数的平方
func square(in <-chan int) <-chan int {
out := make(chan int)
go func() {
for i := range in {
out <- i * i
}
close(out)
}()
return out
}
func main() {
// 构建pipeline:generate -> square
for num := range square(generate()) {
fmt.Println(num) // 输出0,1,4,9,...,81
}
}
说明:generate函数生成数据,square函数处理数据,pipeline模式提高了代码的可读性和可维护性。
sync.Mutex或sync.RWMutex保护。make(chan T))会阻塞发送/接收操作,缓冲channel(make(chan T, size))可提高吞吐量,但需根据场景选择。通过本教程,你已掌握Debian下Golang并发编程的基础知识。建议通过官方文档进一步学习select语句、context包等高级特性,提升并发编程能力。