在Go语言(Golang)中,实现并发编程主要依赖于两个关键特性:goroutines和channels。以下是如何在Linux上使用这两个特性来实现并发编程的简要指南。
Goroutines是Go语言中的轻量级线程,由Go运行时管理。它们比传统的操作系统线程更轻量级,可以轻松创建成千上万个。
创建Goroutine
要创建一个goroutine,只需在函数调用前加上关键字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来执行printNumbers函数
time.Sleep(6 * time.Second) // 主goroutine等待6秒,以确保子goroutine有足够的时间完成
}
Channels是Go语言中用于在goroutines之间进行通信和同步的原语。它们提供了一种安全的方式来传递数据,避免了竞态条件。
创建和使用Channel
package main
import (
"fmt"
)
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum // 将结果发送到channel
close(c) // 关闭channel
}
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int) // 创建一个int类型的channel
go sum(s[:len(s)/2], c) // 启动一个goroutine来计算数组的前半部分和
go sum(s[len(s)/2:], c) // 启动另一个goroutine来计算数组的后半部分和
x, y := <-c, <-c // 从channel接收两个结果
fmt.Println(x, y, x+y)
}
除了使用channels进行通信外,Go还提供了其他同步机制,如sync.WaitGroup
和sync.Mutex
。
使用sync.WaitGroup
sync.WaitGroup
用于等待一组goroutines完成。
package main
import (
"fmt"
"sync"
"time"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done() // 在函数结束时调用Done()来通知WaitGroup该goroutine已完成
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) // 增加WaitGroup的计数器
go worker(i, &wg)
}
wg.Wait() // 等待所有goroutines完成
}
使用sync.Mutex
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.Println("Counter:", counter)
}
通过结合使用goroutines、channels和同步原语,你可以在Linux上轻松实现高效的并发编程。