引言

协程(goroutine)是Go语言并发编程的核心,它允许程序并发执行多个任务,同时保持资源消耗低。本篇文章将通过10个实用例子,帮助读者轻松入门协程编程。

一、什么是协程?

协程是轻量级的线程,由Go运行时管理。它可以在单个线程内并发执行多个任务,并且比线程更轻量,创建和切换的开销更小。

二、创建协程

在Go中,使用go关键字可以创建一个新的协程。以下是一个简单的例子:

package main

import "fmt"

func main() {
    go sayHello()
    sayHello()
}

func sayHello() {
    fmt.Println("Hello, World!")
}

在这个例子中,sayHello函数在一个新的协程中并发执行。

三、示例1:打印数字序列

package main

import (
    "fmt"
    "time"
)

func main() {
    for i := 0; i < 10; i++ {
        go printNumber(i)
    }
}

func printNumber(i int) {
    time.Sleep(time.Second)
    fmt.Println(i)
}

在这个例子中,我们创建了10个协程,每个协程打印一个数字序列。

四、示例2:使用通道进行通信

package main

import (
    "fmt"
    "time"
)

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

    go func() {
        for i := 0; i < 5; i++ {
            ch <- i
            time.Sleep(time.Second)
        }
        close(ch)
    }()

    for num := range ch {
        fmt.Println(num)
    }
}

在这个例子中,我们使用通道ch在主协程和另一个协程之间进行通信。

五、示例3:并发读取文件

package main

import (
    "bufio"
    "fmt"
    "os"
    "sync"
)

func main() {
    file, err := os.Open("example.txt")
    if err != nil {
        panic(err)
    }
    defer file.Close()

    var wg sync.WaitGroup
    reader := bufio.NewReader(file)

    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            line, _, err := reader.ReadLine()
            if err != nil {
                panic(err)
            }
            fmt.Println(string(line))
        }()
    }

    wg.Wait()
}

在这个例子中,我们使用协程并发读取文件中的每一行。

六、示例4:使用WaitGroup同步协程

package main

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

func main() {
    var wg sync.WaitGroup

    for i := 0; i < 5; i++ {
        wg.Add(1)
        go func(i int) {
            defer wg.Done()
            time.Sleep(time.Duration(i) * time.Second)
            fmt.Println(i)
        }(i)
    }

    wg.Wait()
}

在这个例子中,我们使用WaitGroup来同步5个协程的执行。

七、示例5:使用select处理多个通道

package main

import (
    "fmt"
    "time"
)

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

    go func() {
        for i := 0; i < 5; i++ {
            ch1 <- i
            time.Sleep(time.Second)
        }
        close(ch1)
    }()

    go func() {
        for i := 0; i < 5; i++ {
            ch2 <- i
            time.Sleep(time.Second)
        }
        close(ch2)
    }()

    for {
        select {
        case num := <-ch1:
            fmt.Println("From ch1:", num)
        case num := <-ch2:
            fmt.Println("From ch2:", num)
        }
    }
}

在这个例子中,我们使用select语句同时处理两个通道的数据。

八、示例6:使用Mutex保护共享资源

package main

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

func main() {
    var wg sync.WaitGroup
    var counter int
    var mutex sync.Mutex

    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            mutex.Lock()
            counter++
            fmt.Println("Counter:", counter)
            mutex.Unlock()
        }()
    }

    wg.Wait()
}

在这个例子中,我们使用Mutex