CentOS上Golang并發編程實踐指南
Golang以“原生并發”為核心優勢,其輕量級線程(goroutine)、通道(channel)及豐富的同步原語(sync包),使其在CentOS等多平臺上能高效處理并發任務。以下是CentOS環境下Golang并發編程的具體實踐與關鍵要點:
在CentOS上使用Golang前,需完成環境配置:
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是Golang并發的基礎,使用go
關鍵字啟動,由Go運行時管理,內存占用遠小于傳統線程(約2KB)。示例:啟動5個goroutine打印編號:
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() // 等待所有goroutine完成
}
關鍵點:通過sync.WaitGroup
同步goroutine,避免主程序提前退出。
Channel用于goroutine間的數據傳遞,避免共享內存帶來的競態條件。示例:通過帶緩沖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)) // 帶緩沖channel
for _, url := range urls {
go download(url, ch)
}
for i := 0; i < len(urls); i++ {
fmt.Println(<-ch) // 接收并打印結果
}
}
關鍵點:帶緩沖channel可提高并發效率,避免發送操作阻塞。
package main
import (
"fmt"
"sync"
)
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
}
關鍵點:讀寫操作需用Lock()
/Unlock()
包裹,確保原子性。適用于CPU密集型任務,避免goroutine過多導致資源耗盡。示例:創建3個worker處理5個任務:
package main
import "fmt"
func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
fmt.Printf("Worker %d processing job %d\n", id, j)
results <- j * 2 // 模擬任務處理
}
}
func main() {
jobs := make(chan int, 5)
results := make(chan int, 5)
// 啟動3個worker
for w := 1; w <= 3; w++ {
go worker(w, jobs, results)
}
// 發送任務
for j := 1; j <= 5; j++ {
jobs <- j
}
close(jobs)
// 接收結果
for a := 1; a <= 5; a++ {
fmt.Println("Result:", <-results)
}
}
關鍵點:通過帶緩沖的jobs通道控制任務隊列,results通道收集結果。
用于傳遞取消信號、超時或截止時間,避免goroutine泄漏。示例:使用context取消長時間運行的任務:
package main
import (
"context"
"fmt"
"time"
)
func longTask(ctx context.Context, id int) {
for {
select {
case <-ctx.Done():
fmt.Printf("Task %d cancelled\n", id)
return
default:
fmt.Printf("Task %d running...\n", id)
time.Sleep(500 * time.Millisecond)
}
}
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel() // 釋放資源
go longTask(ctx, 1)
time.Sleep(3 * time.Second) // 主程序等待
}
關鍵點:WithTimeout
設置2秒超時,超時后ctx.Done()
觸發,goroutine退出。
-race
標志:go run -race main.go
或測試時使用:go test -race ./...
sync/atomic
包提升性能:package main
import (
"fmt"
"sync/atomic"
)
func main() {
var counter int32
for i := 0; i < 1000; i++ {
go func() {
atomic.AddInt32(&counter, 1)
}()
}
time.Sleep(time.Second)
fmt.Println("Counter:", atomic.LoadInt32(&counter)) // 輸出1000
}
GOMAXPROCS
設置并行度(默認為CPU核心數),優化并發性能。