第6章:Go语言并发编程

第6章:Go语言并发编程

6.1 并发基础概念

6.1.1 并发vs并行

go 复制代码
// 并发示例:模拟多任务处理
func main() {
    // 并发执行多个任务
    go task1()
    go task2()
    
    // 主goroutine继续执行
    time.Sleep(time.Second)
}

func task1() {
    fmt.Println("任务1执行")
}

func task2() {
    fmt.Println("任务2执行")
}

6.1.2 Goroutine

go 复制代码
// Goroutine基本使用
func printNumbers() {
    for i := 1; i <= 5; i++ {
        time.Sleep(100 * time.Millisecond)
        fmt.Printf("数字:%d\n", i)
    }
}

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

func main() {
    go printNumbers()
    go printLetters()
    
    // 等待goroutine执行
    time.Sleep(time.Second)
}

6.2 通道(Channel)

6.2.1 基本通道操作

go 复制代码
func main() {
    // 创建无缓冲通道
    ch := make(chan int)
    
    // 发送和接收
    go func() {
        ch <- 42  // 发送
    }()
    
    value := <-ch  // 接收
    fmt.Println(value)
}

// 带缓冲的通道
func bufferedChannelDemo() {
    ch := make(chan string, 3)
    
    ch <- "Hello"
    ch <- "World"
    ch <- "Go"
    
    fmt.Println(<-ch)  // 依次输出
}

6.2.2 通道方向

go 复制代码
// 只读通道
func receiver(ch <-chan int) {
    for value := range ch {
        fmt.Println("接收:", value)
    }
}

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

func main() {
    ch := make(chan int)
    
    go sender(ch)
    receiver(ch)
}

6.3 并发模式

6.3.1 生产者-消费者模式

go 复制代码
func producer(ch chan<- int) {
    for i := 0; i < 10; i++ {
        ch <- i
        time.Sleep(100 * time.Millisecond)
    }
    close(ch)
}

func consumer(ch <-chan int, done chan<- bool) {
    for value := range ch {
        fmt.Println("消费:", value)
    }
    done <- true
}

func main() {
    ch := make(chan int)
    done := make(chan bool)
    
    go producer(ch)
    go consumer(ch, done)
    
    <-done  // 等待消费者完成
}

6.3.2 select多路复用

go 复制代码
func main() {
    ch1 := make(chan string)
    ch2 := make(chan string)
    
    go func() {
        time.Sleep(time.Second)
        ch1 <- "通道1"
    }()
    
    go func() {
        time.Sleep(2 * time.Second)
        ch2 <- "通道2"
    }()
    
    select {
    case msg1 := <-ch1:
        fmt.Println(msg1)
    case msg2 := <-ch2:
        fmt.Println(msg2)
    case <-time.After(3 * time.Second):
        fmt.Println("超时")
    }
}

6.4 同步原语

6.4.1 互斥锁

go 复制代码
type SafeCounter struct {
    mu sync.Mutex
    counter int
}

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

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

func main() {
    counter := &SafeCounter{}
    
    for i := 0; i < 1000; i++ {
        go counter.Increment()
    }
    
    time.Sleep(time.Second)
    fmt.Println(counter.Value())
}

6.4.2 读写锁

go 复制代码
type Cache struct {
    mu sync.RWMutex
    data map[string]int
}

func (c *Cache) Read(key string) (int, bool) {
    c.mu.RLock()
    defer c.mu.RUnlock()
    value, ok := c.data[key]
    return value, ok
}

func (c *Cache) Write(key string, value int) {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.data[key] = value
}

6.4.3 原子操作

go 复制代码
var counter int64

func incrementCounter() {
    atomic.AddInt64(&counter, 1)
}

func getCounter() int64 {
    return atomic.LoadInt64(&counter)
}

6.5 并发实践

6.5.1 并行爬虫

go 复制代码
func fetchURL(url string, ch chan<- string) {
    resp, err := http.Get(url)
    if err != nil {
        ch <- fmt.Sprintf("错误: %v", err)
        return
    }
    defer resp.Body.Close()
    
    body, _ := ioutil.ReadAll(resp.Body)
    ch <- fmt.Sprintf("URL: %s, 长度: %d", url, len(body))
}

func main() {
    urls := []string{
        "https://www.example.com",
        "https://www.google.com",
        "https://www.github.com",
    }
    
    ch := make(chan string, len(urls))
    
    for _, url := range urls {
        go fetchURL(url, ch)
    }
    
    for i := 0; i < len(urls); i++ {
        fmt.Println(<-ch)
    }
}

6.5.2 并发限流

go 复制代码
func worker(id int, jobs <-chan int, results chan<- int) {
    for job := range jobs {
        fmt.Printf("Worker %d 处理任务 %d\n", id, job)
        time.Sleep(time.Second)
        results <- job * 2
    }
}

func main() {
    jobs := make(chan int, 100)
    results := make(chan int, 100)
    
    // 创建固定数量的工作goroutine
    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(<-results)
    }
}

实践项目:简单的并发聊天服务器

go 复制代码
type Client struct {
    conn net.Conn
    send chan string
}

type ChatServer struct {
    clients    map[*Client]bool
    broadcast  chan string
    register   chan *Client
    unregister chan *Client
}

func (server *ChatServer) run() {
    for {
        select {
        case client := <-server.register:
            server.clients[client] = true
        case client := <-server.unregister:
            if _, ok := server.clients[client]; ok {
                delete(server.clients, client)
                close(client.send)
            }
        case message := <-server.broadcast:
            for client := range server.clients {
                select {
                case client.send <- message:
                default:
                    close(client.send)
                    delete(server.clients, client)
                }
            }
        }
    }
}
相关推荐
BinaryBardC8 分钟前
Objective-C语言的网络编程
开发语言·后端·golang
鹿屿二向箔11 分钟前
一个基于Spring Boot的简单网吧管理系统
spring boot·后端·python
java熊猫12 分钟前
Clojure语言的多线程编程
开发语言·后端·golang
废柴小z13 分钟前
THREE.js的VideoTexture以及CanvasTexture在部分浏览器以及小程序webview中纯黑不起作用的解决办法
开发语言·javascript·小程序
连胜优佳16 分钟前
20、javase-API.容器
java·开发语言
云端 架构师36 分钟前
Elixir语言的语法糖
开发语言·后端·golang
PieroPc1 小时前
做一个 简单的Django 《股票自选助手》显示 用akshare 库(A股数据获取)
后端·python·django
涛ing1 小时前
12. C语言 数组与指针(深入理解)
linux·c语言·开发语言·数据结构·c++·算法·ubuntu
计算机-秋大田1 小时前
基于Spring Boot的扶贫助农系统设计与实现(LW+页码+讲解)
java·vue.js·spring boot·后端·课程设计
byte轻骑兵1 小时前
嵌入式C语言:二维数组
c语言·开发语言