欢迎光临
我们一直在努力

第七章:并发编程

第七章:并发编程

7.1 Goroutine

Goroutine基础

package main

import (
"fmt"
"time"
)

// 普通函数
func printNumbers() {
for i := 1; i <= 5; i++ {
fmt.Printf("数字: %d\\n", i)
time.Sleep(100 * time.Millisecond)
}
}

func printLetters() {
for ch := 'A'; ch <= 'E'; ch++ {
fmt.Printf("字母: %c\\n", ch)
time.Sleep(150 * time.Millisecond)
}
}

func main() {
// 顺序执行
fmt.Println("顺序执行:")
printNumbers()
printLetters()

// 并发执行
fmt.Println("\\n并发执行:")
go printNumbers() // 启动goroutine
go printLetters() // 启动goroutine

// 等待goroutine完成
time.Sleep(2 * time.Second)
fmt.Println("主函数结束")
}

WaitGroup

package main

import (
"fmt"
"sync"
"time"
)

func worker(id int, wg *sync.WaitGroup) {
defer wg.Done() // 完成时通知WaitGroup

fmt.Printf("Worker %d 开始工作\\n", id)
time.Sleep(time.Duration(id) * 100 * time.Millisecond)
fmt.Printf("Worker %d 完成工作\\n", id)
}

func main() {
var wg sync.WaitGroup

// 启动5个worker
for i := 1; i <= 5; i++ {
wg.Add(1) // 增加计数器
go worker(i, &wg)
}

// 等待所有worker完成
wg.Wait()
fmt.Println("所有worker已完成")
}

Mutex互斥锁

package main

import (
"fmt"
"sync"
)

// SafeCounter 线程安全的计数器
type SafeCounter struct {
mu sync.Mutex
count int
}

func (c *SafeCounter) Increment() {
c.mu.Lock()
defer c.mu.Unlock()
c.count++
}

func (c *SafeCounter) Decrement() {
c.mu.Lock()
defer c.mu.Unlock()
c.count—
}

func (c *SafeCounter) Value() int {
c.mu.Lock()
defer c.mu.Unlock()
return c.count
}

func main() {
counter := &SafeCounter{}
var wg sync.WaitGroup

// 启动100个goroutine递增
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
counter.Increment()
}()
}

// 启动50个goroutine递减
for i := 0; i < 50; i++ {
wg.Add(1)
go func() {
defer wg.Done()
counter.Decrement()
}()
}

wg.Wait()
fmt.Printf("最终计数: %d\\n", counter.Value()) // 应该是50
}

RWMutex读写锁

package main

import (
"fmt"
"sync"
"time"
)

// SafeMap 线程安全的Map
type SafeMap struct {
mu sync.RWMutex
data map[string]string
}

func NewSafeMap() *SafeMap {
return &SafeMap{
data: make(map[string]string),
}
}

func (m *SafeMap) Get(key string) (string, bool) {
m.mu.RLock() // 读锁
defer m.mu.RUnlock()
val, ok := m.data[key]
return val, ok
}

func (m *SafeMap) Set(key, value string) {
m.mu.Lock() // 写锁
defer m.mu.Unlock()
m.data[key] = value
}

func (m *SafeMap) Delete(key string) {
m.mu.Lock()
defer m.mu.Unlock()
delete(m.data, key)
}

func (m *SafeMap) Len() int {
m.mu.RLock()
defer m.mu.RUnlock()
return len(m.data)
}

func main() {
sm := NewSafeMap()
var wg sync.WaitGroup

// 并发写入
for i := 0; i < 10; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
key := fmt.Sprintf("key%d", id)
value := fmt.Sprintf("value%d", id)
sm.Set(key, value)
fmt.Printf("写入: %s = %s\\n", key, value)
}(i)
}

// 并发读取
for i := 0; i < 10; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
key := fmt.Sprintf("key%d", id)
time.Sleep(50 * time.Millisecond)
if val, ok := sm.Get(key); ok {
fmt.Printf("读取: %s = %s\\n", key, val)
}
}(i)
}

wg.Wait()
fmt.Printf("Map大小: %d\\n", sm.Len())
}

7.2 Channel

Channel基础

package main

import "fmt"

func main() {
// 创建channel
ch := make(chan int)

// 发送数据到channel
go func() {
ch <- 42 // 发送
}()

// 从channel接收数据
value := <-ch // 接收
fmt.Printf("接收到: %d\\n", value)

// 带缓冲的channel
bufferedCh := make(chan string, 3)

bufferedCh <- "Hello"
bufferedCh <- "World"
bufferedCh <- "Go"

fmt.Println(<-bufferedCh) // Hello
fmt.Println(<-bufferedCh) // World
fmt.Println(<-bufferedCh) // Go
}

Channel方向

package main

import "fmt"

// 只写channel
func producer(ch chan<- int) {
for i := 0; i < 5; i++ {
ch <- i
}
close(ch)
}

// 只读channel
func consumer(ch <-chan int) {
for value := range ch {
fmt.Printf("消费: %d\\n", value)
}
}

func main() {
ch := make(chan int)

go producer(ch)
consumer(ch)
}

Select语句

package main

import (
"fmt"
"time"
)

func main() {
ch1 := make(chan string)
ch2 := make(chan string)

go func() {
time.Sleep(1 * time.Second)
ch1 <- "来自ch1"
}()

go func() {
time.Sleep(2 * time.Second)
ch2 <- "来自ch2"
}()

// 使用select等待多个channel
for i := 0; i < 2; i++ {
select {
case msg1 := <-ch1:
fmt.Println(msg1)
case msg2 := <-ch2:
fmt.Println(msg2)
}
}

// select超时控制
ch := make(chan string)
go func() {
time.Sleep(3 * time.Second)
ch <- "数据"
}()

select {
case msg := <-ch:
fmt.Println("收到:", msg)
case <-time.After(2 * time.Second):
fmt.Println("超时!")
}

// 非阻塞select
ch3 := make(chan int, 1)

select {
case v := <-ch3:
fmt.Println("收到:", v)
default:
fmt.Println("没有数据")
}

ch3 <- 42

select {
case v := <-ch3:
fmt.Println("收到:", v)
default:
fmt.Println("没有数据")
}
}

Channel模式

package main

import (
"fmt"
"sync"
)

// 扇出模式 (Fan-out)
func fanOut(input <-chan int, workers int) []<-chan int {
channels := make([]<-chan int, workers)
for i := 0; i < workers; i++ {
channels[i] = worker(input, i)
}
return channels
}

func worker(input <-chan int, id int) <-chan int {
output := make(chan int)
go func() {
defer close(output)
for v := range input {
result := v * v // 处理数据
fmt.Printf("Worker %d: %d -> %d\\n", id, v, result)
output <- result
}
}()
return output
}

// 扇入模式 (Fan-in)
func fanIn(channels …<-chan int) <-chan int {
var wg sync.WaitGroup
merged := make(chan int)

// 为每个channel启动一个goroutine
wg.Add(len(channels))
for _, ch := range channels {
go func(c <-chan int) {
defer wg.Done()
for v := range c {
merged <- v
}
}(ch)
}

// 等待所有channel关闭后关闭merged
go func() {
wg.Wait()
close(merged)
}()

return merged
}

// 管道模式 (Pipeline)
func pipeline() {
// 第一阶段: 生成数据
nums := make(chan int)
go func() {
defer close(nums)
for i := 1; i <= 10; i++ {
nums <- i
}
}()

// 第二阶段: 平方
squares := make(chan int)
go func() {
defer close(squares)
for n := range nums {
squares <- n * n
}
}()

// 第三阶段: 过滤偶数
evens := make(chan int)
go func() {
defer close(evens)
for n := range squares {
if n%2 == 0 {
evens <- n
}
}
}()

// 消费结果
for n := range evens {
fmt.Println(n)
}
}

func main() {
fmt.Println("管道模式示例:")
pipeline()

fmt.Println("\\n扇出-扇入模式示例:")
// 创建输入channel
input := make(chan int)
go func() {
defer close(input)
for i := 1; i <= 10; i++ {
input <- i
}
}()

// 扇出: 多个worker处理
channels := fanOut(input, 3)

// 扇入: 合并结果
merged := fanIn(channels…)

// 收集结果
results := make([]int, 0)
for v := range merged {
results = append(results, v)
}
fmt.Printf("结果: %v\\n", results)
}

7.3 Context

Context基础

package main

import (
"context"
"fmt"
"time"
)

func worker(ctx context.Context, id int) {
for {
select {
case <-ctx.Done():
fmt.Printf("Worker %d: 收到取消信号, 原因: %v\\n", id, ctx.Err())
return
default:
fmt.Printf("Worker %d: 正在工作…\\n", id)
time.Sleep(500 * time.Millisecond)
}
}
}

func main() {
// 创建可取消的context
ctx, cancel := context.WithCancel(context.Background())

// 启动多个worker
for i := 1; i <= 3; i++ {
go worker(ctx, i)
}

// 3秒后取消所有worker
time.Sleep(3 * time.Second)
fmt.Println("主函数: 发送取消信号")
cancel()

// 等待worker退出
time.Sleep(1 * time.Second)
fmt.Println("主函数: 结束")
}

Context超时和值

package main

import (
"context"
"fmt"
"time"
)

// 模拟HTTP请求处理
func handleRequest(ctx context.Context) {
// 从context获取值
userID, ok := ctx.Value("userID").(string)
if ok {
fmt.Printf("处理用户 %s 的请求\\n", userID)
}

// 模拟长时间操作
select {
case <-time.After(3 * time.Second):
fmt.Println("请求处理完成")
case <-ctx.Done():
fmt.Printf("请求被取消: %v\\n", ctx.Err())
}
}

func main() {
// 超时context
fmt.Println("示例1: 超时context")
ctx1, cancel1 := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel1()

go handleRequest(ctx1)
time.Sleep(3 * time.Second)

// 带截止时间的context
fmt.Println("\\n示例2: 截止时间context")
deadline := time.Now().Add(2 * time.Second)
ctx2, cancel2 := context.WithDeadline(context.Background(), deadline)
defer cancel2()

go handleRequest(ctx2)
time.Sleep(3 * time.Second)

// 带值的context
fmt.Println("\\n示例3: 带值的context")
ctx3 := context.WithValue(context.Background(), "userID", "user123")
ctx3, cancel3 := context.WithTimeout(ctx3, 2*time.Second)
defer cancel3()

go handleRequest(ctx3)
time.Sleep(3 * time.Second)

// context链
fmt.Println("\\n示例4: context链")
parentCtx, parentCancel := context.WithCancel(context.Background())
childCtx, childCancel := context.WithTimeout(parentCtx, 5*time.Second)
defer parentCancel()
defer childCancel()

go func() {
<-childCtx.Done()
fmt.Printf("子context: %v\\n", childCtx.Err())
}()

// 取消父context会影响子context
time.Sleep(1 * time.Second)
parentCancel()
time.Sleep(1 * time.Second)
}

7.4 实战案例:并发下载器

package main

import (
"context"
"fmt"
"math/rand"
"strings"
"sync"
"time"
)

// DownloadTask 下载任务
type DownloadTask struct {
ID int
URL string
}

// DownloadResult 下载结果
type DownloadResult struct {
TaskID int
URL string
Size int
Duration time.Duration
Error error
}

// Downloader 并发下载器
type Downloader struct {
maxWorkers int
tasks chan DownloadTask
results chan DownloadResult
ctx context.Context
cancel context.CancelFunc
wg sync.WaitGroup
}

// NewDownloader 创建下载器
func NewDownloader(maxWorkers int) *Downloader {
ctx, cancel := context.WithCancel(context.Background())
return &Downloader{
maxWorkers: maxWorkers,
tasks: make(chan DownloadTask, 100),
results: make(chan DownloadResult, 100),
ctx: ctx,
cancel: cancel,
}
}

// Start 启动下载器
func (d *Downloader) Start() {
// 启动worker池
for i := 0; i < d.maxWorkers; i++ {
d.wg.Add(1)
go d.worker(i)
}

// 收集结果
go d.collectResults()
}

// worker 工作协程
func (d *Downloader) worker(id int) {
defer d.wg.Done()

for {
select {
case <-d.ctx.Done():
fmt.Printf("Worker %d: 收到停止信号\\n", id)
return
case task, ok := <-d.tasks:
if !ok {
fmt.Printf("Worker %d: 任务通道已关闭\\n", id)
return
}
d.processTask(id, task)
}
}
}

// processTask 处理下载任务
func (d *Downloader) processTask(workerID int, task DownloadTask) {
start := time.Now()

// 模拟下载过程
duration := time.Duration(rand.Intn(3)+1) * time.Second
time.Sleep(duration)

// 模拟随机失败
var err error
if rand.Float32() < 0.1 { // 10%失败率
err = fmt.Errorf("下载失败: 网络错误")
}

size := rand.Intn(1000) + 100

result := DownloadResult{
TaskID: task.ID,
URL: task.URL,
Size: size,
Duration: time.Since(start),
Error: err,
}

d.results <- result
}

// collectResults 收集结果
func (d *Downloader) collectResults() {
for result := range d.results {
if result.Error != nil {
fmt.Printf("任务 %d 失败: %v\\n", result.TaskID, result.Error)
} else {
fmt.Printf("任务 %d 完成: %s (%dKB, 耗时%v)\\n",
result.TaskID, result.URL, result.Size, result.Duration)
}
}
}

// AddTask 添加下载任务
func (d *Downloader) AddTask(task DownloadTask) {
d.tasks <- task
}

// Stop 停止下载器
func (d *Downloader) Stop() {
close(d.tasks)
d.wg.Wait()
close(d.results)
d.cancel()
}

// DownloadManager 下载管理器
type DownloadManager struct {
downloader *Downloader
totalTasks int
completed int
failed int
mu sync.Mutex
}

// NewDownloadManager 创建管理器
func NewDownloadManager(maxWorkers int) *DownloadManager {
return &DownloadManager{
downloader: NewDownloader(maxWorkers),
}
}

// Start 启动管理器
func (dm *DownloadManager) Start() {
dm.downloader.Start()
}

// AddURL 添加URL
func (dm *DownloadManager) AddURL(url string) {
dm.mu.Lock()
dm.totalTasks++
dm.mu.Unlock()

dm.downloader.AddTask(DownloadTask{
ID: dm.totalTasks,
URL: url,
})
}

// Stop 停止管理器
func (dm *DownloadManager) Stop() {
dm.downloader.Stop()
}

func main() {
// 创建下载管理器
manager := NewDownloadManager(3) // 3个worker

// 启动
manager.Start()

// 添加下载任务
urls := []string{
"https://example.com/file1.zip",
"https://example.com/file2.zip",
"https://example.com/file3.zip",
"https://example.com/file4.zip",
"https://example.com/file5.zip",
"https://example.com/file6.zip",
"https://example.com/file7.zip",
"https://example.com/file8.zip",
"https://example.com/file9.zip",
"https://example.com/file10.zip",
}

for _, url := range urls {
manager.AddURL(url)
}

// 等待完成
time.Sleep(10 * time.Second)

// 停止
manager.Stop()

fmt.Println("\\n下载完成!")
}

7.5 sync包常用工具

sync.Once

package main

import (
"fmt"
"sync"
)

var once sync.Once
var config map[string]string

func loadConfig() {
fmt.Println("加载配置…")
config = map[string]string{
"host": "localhost",
"port": "8080",
}
}

func GetConfig() map[string]string {
once.Do(loadConfig) // 只执行一次
return config
}

func main() {
var wg sync.WaitGroup

// 多个goroutine同时获取配置
for i := 0; i < 5; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
cfg := GetConfig()
fmt.Printf("Goroutine %d: %v\\n", id, cfg)
}(i)
}

wg.Wait()
}

sync.Pool

package main

import (
"fmt"
"sync"
)

type Buffer struct {
Data []byte
}

func NewBuffer() *Buffer {
fmt.Println("创建新Buffer")
return &Buffer{
Data: make([]byte, 0, 1024),
}
}

func (b *Buffer) Reset() {
b.Data = b.Data[:0]
}

func main() {
// 创建对象池
pool := sync.Pool{
New: func() interface{} {
return NewBuffer()
},
}

// 从池中获取对象
buf1 := pool.Get().(*Buffer)
buf1.Data = append(buf1.Data, "Hello"…)
fmt.Printf("buf1: %s\\n", buf1.Data)

// 归还到池中
buf1.Reset()
pool.Put(buf1)

// 再次获取(可能重用之前的对象)
buf2 := pool.Get().(*Buffer)
fmt.Printf("buf2: %s (长度: %d)\\n", buf2.Data, len(buf2.Data))

// 并发使用
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
buf := pool.Get().(*Buffer)
buf.Data = append(buf.Data, fmt.Sprintf("goroutine-%d", id)…)
fmt.Printf("Goroutine %d: %s\\n", id, buf.Data)
buf.Reset()
pool.Put(buf)
}(i)
}
wg.Wait()
}

sync.Map

package main

import (
"fmt"
"sync"
)

func main() {
var m sync.Map

// 存储
m.Store("name", "张三")
m.Store("age", 25)
m.Store("city", "北京")

// 读取
name, ok := m.Load("name")
if ok {
fmt.Printf("name: %v\\n", name)
}

// 存储或获取
actual, loaded := m.LoadOrStore("name", "李四")
fmt.Printf("actual: %v, loaded: %v\\n", actual, loaded)

// 删除
m.Delete("age")

// 遍历
m.Range(func(key, value interface{}) bool {
fmt.Printf("%v: %v\\n", key, value)
return true
})

// 并发安全
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
key := fmt.Sprintf("key%d", id)
m.Store(key, id)
}(i)
}
wg.Wait()

fmt.Println("\\n并发写入后的数据:")
m.Range(func(key, value interface{}) bool {
fmt.Printf("%v: %v\\n", key, value)
return true
})
}

赞(0)
未经允许不得转载:171主机测评 » 第七章:并发编程
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址