基础 goroutine 启动
题目描述
启动一个协程打印数字
- 定义函数
printNum(),循环打印 1~5- 在
main中使用 go printNum() 启动协程- 主协程等待一段时间,让子协程执行完毕
输出示例
主协程等待...
协程打印: 1
协程打印: 2
协程打印: 3
协程打印: 4
协程打印: 5
主协程结束
实现代码
Go
package main
import (
"fmt"
"time"
)
// 普通函数
func printNum() {
for i := 1; i <= 5; i++ {
fmt.Println("协程打印:", i)
time.Sleep(200 * time.Millisecond)
}
}
func main() {
// 启动 goroutine
go printNum()
// 主协程等待
fmt.Println("主协程等待...")
time.Sleep(1 * time.Second)
fmt.Println("主协程结束")
}
多个 goroutine 同时运行
题目描述
启动两个协程并发执行
- 定义函数
task1()打印 A~C- 定义函数
task2()打印 1~3- 同时启动两个协程
- 观察并发执行效果
输出示例
协程1: A
协程2: 1
协程1: B
协程2: 2
协程1: C
协程2: 3
程序结束
实现代码
Go
package main
import (
"fmt"
"time"
)
func task1() {
for i := 'A'; i <= 'C'; i++ {
fmt.Printf("协程1:%c\n", i)
time.Sleep(200 * time.Millisecond)
}
}
func task2() {
for i := 1; i <= 3; i++ {
fmt.Println("协程2:", i)
time.Sleep(200 * time.Millisecond)
}
}
func main() {
go task1()
go task2()
// 等待协程执行完
time.Sleep(1 * time.Second)
fmt.Println("程序结束")
}
三个打印机同时打印
题目描述
办公室有3台打印机,同时打印不同的文件。每台打印机打印5页,每页需要0.3秒。
要求:
创建3个goroutine模拟3台打印机
每台打印机打印5页,每打印一页输出:
打印机X 打印了第Y页使用
time.Sleep等待所有打印机完成最后输出:
所有文件打印完成
输出示例
打印机2 开始工作...
打印机1 开始工作...
打印机3 开始工作...
打印机1 打印了第1页
打印机2 打印了第1页
打印机3 打印了第1页
打印机1 打印了第2页
打印机2 打印了第2页
打印机3 打印了第2页
打印机1 打印了第3页
打印机2 打印了第3页
打印机3 打印了第3页
打印机1 打印了第4页
打印机2 打印了第4页
打印机3 打印了第4页
打印机1 打印了第5页
打印机1 打印完成!
打印机2 打印了第5页
打印机2 打印完成!
打印机3 打印了第5页
打印机3 打印完成!
所有文件打印完成
实现代码
Go
package main
import (
"fmt"
"time"
)
func printFile(printerID int, pages int) {
fmt.Printf("打印机%d 开始工作...\n", printerID)
for page := 1; page <= pages; page++ {
time.Sleep(300 * time.Millisecond)
fmt.Printf("打印机%d 打印了第%d页\n", printerID, page)
}
fmt.Printf("打印机%d 打印完成!\n", printerID)
}
func main() {
// 启动3台打印机
go printFile(1, 5)
go printFile(2, 5)
go printFile(3, 5)
// 等待所有打印机完成(5页 × 0.3秒 = 1.5秒)
time.Sleep(2 * time.Second)
fmt.Println("所有文件打印完成")
}
goroutine + channel 通道传值
题目描述
协程通过通道发送数据
- 创建通道
ch- 启动协程,向通道发送数字
100- 主协程从通道接收数据并打印
输出示例
协程发送数据:100
主协程接收: 100
实现代码
Go
package main
import "fmt"
func sendData(ch chan int) {
fmt.Println("协程发送数据:100")
ch <- 100 // 发送到通道
}
func main() {
// 创建通道
ch := make(chan int)
// 启动协程
go sendData(ch)
// 主协程接收
data := <-ch
fmt.Println("主协程接收:", data)
}
并发计算求和(多协程分摊计算任务)
题目描述
多 goroutine 并发计算 1~100 的总和
- 启动 2 个协程
- 协程 1 计算 1~50 的和
- 协程 2 计算 51~100 的和
- 通过 channel 将结果传回主协程
- 主协程汇总输出最终总和
输出示例
1~50 的和: 1275
51~100 的和: 3775
总和: 5050
实现代码
Go
package main
import "fmt"
// 计算从 start 到 end 的和,通过 ch 发送结果
func sum(start, end int, ch chan int) {
total := 0
for i := start; i <= end; i++ {
total += i
}
ch <- total
}
func main() {
ch := make(chan int)
// 启动两个协程分摊任务
go sum(1, 50, ch)
go sum(51, 100, ch)
// 接收两个结果
s1 := <-ch
s2 := <-ch
fmt.Println("1~50 的和:", s1)
fmt.Println("51~100 的和:", s2)
fmt.Println("总和:", s1+s2)
}
最大值查找器
题目描述
有一个包含12个数字的数组,创建3个goroutine,每个负责查找一部分数字中的最大值,通过channel返回,主程序找出全局最大值。
要求:
数组:[23, 56, 12, 89, 45, 67, 34, 91, 28, 73, 19, 88]
分成3组:第1组索引0-3,第2组索引4-7,第3组索引8-11
每个goroutine找出自己组内的最大值
使用channel传递结果
主程序找出全局最大值并打印
输出示例
第1组 [23 56 12 89] 最大值: 89
第2组 [45 67 34 91] 最大值: 91
第3组 [28 73 19 88] 最大值: 88
全局最大值: 91
实现代码
Go
package main
import (
"fmt"
)
func findMax(nums []int, groupID int, ch chan int) {
max := nums[0]
for _, num := range nums {
if num > max {
max = num
}
}
fmt.Printf("第%d组 %v 最大值: %d\n", groupID, nums, max)
ch <- max
}
func main() {
ch := make(chan int)
numbers := []int{23, 56, 12, 89, 45, 67, 34, 91, 28, 73, 19, 88}
// 分成3组
group1 := numbers[0:4] // [23 56 12 89]
group2 := numbers[4:8] // [45 67 34 91]
group3 := numbers[8:12] // [28 73 19 88]
// 启动3个goroutine
go findMax(group1, 1, ch)
go findMax(group2, 2, ch)
go findMax(group3, 3, ch)
// 接收3个结果,找出全局最大值
globalMax := 0
for i := 0; i < 3; i++ {
max := <-ch
if max > globalMax {
globalMax = max
}
}
fmt.Printf("全局最大值: %d\n", globalMax)
}
简单的生产者消费者
题目描述
一个生产者生产数字,一个消费者消费数字。生产者每1秒生产一个数字(1-5),消费者每2秒消费一个数字。
要求:
使用无缓冲channel
生产者发送5个数字
消费者接收并打印
输出示例
生产者: 生产 1
消费者: 消费 1
生产者: 生产 2
消费者: 消费 2
生产者: 生产 3
消费者: 消费 3
生产者: 生产 4
消费者: 消费 4
生产者: 生产 5
消费者: 消费 5
生产消费完成
实现代码
Go
package main
import (
"fmt"
"time"
)
func producer(ch chan int) {
for i := 1; i <= 5; i++ {
time.Sleep(1 * time.Second)
fmt.Printf("生产者: 生产 %d\n", i)
ch <- i
}
close(ch)
}
func consumer(ch chan int) {
for num := range ch {
time.Sleep(2 * time.Second)
fmt.Printf("消费者: 消费 %d\n", num)
}
}
func main() {
ch := make(chan int)
go producer(ch)
consumer(ch)
fmt.Println("生产消费完成")
}
sync.WaitGroup 等待所有协程完成
题目描述
使用 WaitGroup 等待多个协程
- 使用
sync.WaitGroup等待 2 个协程- 每个协程执行完调用
Done()- 主协程调用
Wait()阻塞等待
输出示例
协程 1 正在运行
协程 2 正在运行
所有协程执行完毕
实现代码
Go
package main
import (
"fmt"
"sync"
)
func worker(id int, wg *sync.WaitGroup) {
// 函数结束时通知完成
defer wg.Done()
fmt.Printf("协程 %d 正在运行\n", id)
}
func main() {
// 创建等待组
var wg sync.WaitGroup
// 等待 2 个协程
wg.Add(2)
// 启动协程
go worker(1, &wg)
go worker(2, &wg)
// 阻塞等待所有协程完成
wg.Wait()
fmt.Println("所有协程执行完毕")
}
生产者 --- 消费者模型
题目描述
goroutine + channel 实现生产者消费者
- 生产者协程:产生 1~5 数字,发送到通道
- 消费者协程:从通道读取并处理数据
- 通道关闭后消费者退出
- 使用 WaitGroup 等待完成
输出示例
处理任务:1
处理任务:2
处理任务:3
处理任务:4
处理任务:5
所有任务处理完成
实现代码
Go
package main
import (
"fmt"
"sync"
)
// 生产者:发送数据
func producer(ch chan<- int, wg *sync.WaitGroup) {
defer wg.Done()
for i := 1; i <= 5; i++ {
ch <- i
}
close(ch) // 发送完关闭通道
}
// 消费者:接收处理
func consumer(ch <-chan int, wg *sync.WaitGroup) {
defer wg.Done()
for num := range ch {
fmt.Printf("处理任务:%d\n", num)
}
}
func main() {
ch := make(chan int)
var wg sync.WaitGroup
wg.Add(2)
go producer(ch, &wg)
go consumer(ch, &wg)
wg.Wait()
fmt.Println("所有任务处理完成")
}
模拟并发下载文件
题目描述
使用 goroutine 模拟并发下载多个文件
- 定义函数 download (file string),模拟下载耗时
- 同时下载 3 个文件,用 WaitGroup 等待全部完成
- 输出每个文件开始、完成信息
输出示例
开始下载:a.jpg
开始下载:b.mp4
开始下载:c.zip
下载完成:a.jpg
下载完成:b.mp4
下载完成:c.zip
所有文件下载完成
实现代码
Go
package main
import (
"fmt"
"sync"
"time"
)
func download(file string, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("开始下载:%s\n", file)
time.Sleep(1 * time.Second) // 模拟下载耗时
fmt.Printf("下载完成:%s\n", file)
}
func main() {
var wg sync.WaitGroup
files := []string{"a.jpg", "b.mp4", "c.zip"}
wg.Add(len(files))
for _, f := range files {
go download(f, &wg)
}
wg.Wait()
fmt.Println("所有文件下载完成")
}
多路等待多个任务
题目描述
- 启动 2 个协程,分别向
ch1、ch2发送字符串- 使用
select同时监听两个通道- 打印先到达的消息
输出示例
来自任务2的消息
实现代码
Go
package main
import (
"fmt"
"time"
)
func send1(ch chan string) {
time.Sleep(200 * time.Millisecond)
ch <- "来自任务1的消息"
}
func send2(ch chan string) {
time.Sleep(100 * time.Millisecond)
ch <- "来自任务2的消息"
}
func main() {
ch1 := make(chan string)
ch2 := make(chan string)
go send1(ch1)
go send2(ch2)
// 多路复用:谁先完成处理谁
select {
case msg1 := <-ch1:
fmt.Println(msg1)
case msg2 := <-ch2:
fmt.Println(msg2)
}
}
多商家接单
题目描述
用户下单后,系统同时向 麦当劳 、肯德基 、华莱士 三个商家发送订单。每个商家处理时间不同(1-3秒随机),哪个商家先回复就采用哪个,其他商家的请求自动取消。
用3个 goroutine 模拟三个商家,各自随机延迟1-3秒后回复
用
select同时等待三个商家的回复只处理第一个回复的商家,打印"XXX接单成功"
输出示例
等待商家接单...
肯德基接单成功
实现代码
Go
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
// 创建三个商家通道
mcd := make(chan string)
kfc := make(chan string)
hl := make(chan string)
// 麦当劳
go func() {
time.Sleep(time.Duration(1+rand.Intn(3)) * time.Second)
mcd <- "麦当劳"
}()
// 肯德基
go func() {
time.Sleep(time.Duration(1+rand.Intn(3)) * time.Second)
kfc <- "肯德基"
}()
// 华莱士
go func() {
time.Sleep(time.Duration(1+rand.Intn(3)) * time.Second)
hl <- "华莱士"
}()
fmt.Println("等待商家接单...")
// 哪个先来就选哪个
select {
case name := <-mcd:
fmt.Printf("%s接单成功\n", name)
case name := <-kfc:
fmt.Printf("%s接单成功\n", name)
case name := <-hl:
fmt.Printf("%s接单成功\n", name)
}
}