Goroutine 基础
本课属于 Coddy GO 学习旅程的“面向对象编程”单元。第 59 课,共 107 课。
goroutine 是由 Go 运行时管理的轻量级执行线程。与会占用大量内存的传统线程不同,goroutine 启动时只需几 KB 的栈空间,因此你可以让成千上万个 goroutine 并发运行。
要启动一个 goroutine,只需在函数调用前加上 go 关键字:
func sayHello(name string) {
fmt.Println("Hello,", name)
}
func main() {
go sayHello("Alice") // 并发运行
go sayHello("Bob") // 并发运行
time.Sleep(100 * time.Millisecond)
fmt.Println("Done")
}当执行 go sayHello("Alice") 时,它不会等待 sayHello 执行完毕,而是立即继续执行下一行,同时 sayHello 在后台运行。这就是我们需要 time.Sleep 的原因。没有它,main 会在 goroutine 完成之前退出。
你也可以使用匿名函数启动 goroutine:
go func(msg string) {
fmt.Println(msg)
}("Hello from goroutine")main 函数本身在一个 goroutine 中运行。它返回时,其他所有 goroutine 都会立即终止,没有机会完成。使用 time.Sleep 是一种临时解决方案;在接下来的课程中,你会学习使用通道和等待组进行正确的同步。
挑战
简单我们来构建一个任务执行器,使用 goroutine 并发执行多个任务。你将创建一个简单的系统,让任务在后台运行,同时主程序继续执行,以此演示 goroutine 如何实现并发执行。
你将把代码分成两个文件:
tasks.go:定义任务执行逻辑。创建一个
Task结构体,包含Name(字符串)和Duration(整数,表示毫秒)字段。为
Task实现一个Run()方法,让它通过休眠指定时长来模拟任务执行,然后打印:Task [Name] completed创建一个
RunAllTasks(tasks []Task)函数,将每个任务的Run()方法作为 goroutine 启动。启动所有 goroutine 后,函数应休眠 500 毫秒,以便它们完成,然后打印:All tasks launchedmain.go:读取任务信息,并协调并发执行。读取任务数量,然后读取每个任务的名称和时长。创建这些任务,并将它们传递给
RunAllTasks。函数返回后,打印:Main function done
输入内容如下:
- 第 1 行:任务数量(整数)
- 后续各行:每个任务占两行,第一行为任务名称,第二行为任务时长(毫秒)
例如,给定以下输入:
3
Download
100
Process
50
Upload
75输出应显示任务完成情况(由于并发,顺序可能不同),然后显示完成消息:
Task Process completed
Task Upload completed
Task Download completed
All tasks launched
Main function done注意:由于 goroutine 并发运行,时长较短的任务通常会先完成。任务完成顺序取决于各自的时长,较短的任务会先于较长的任务完成。
使用 time.Sleep、time.Duration 和 time.Millisecond 设置延迟。请记住,如果没有在 RunAllTasks 中休眠,该函数会在 goroutine 完成工作之前返回。
亲手试试
package main
import (
"fmt"
)
func main() {
// 读取任务数量
var numTasks int
fmt.Scanln(&numTasks)
// TODO: 创建一个切片来存放任务
// TODO: 读取每个任务的名称和时长
// 对于每个任务:
// 读取任务名称
// 读取时长(整数)
// 创建一个 Task,并将其添加到你的切片中
// TODO: 用你的任务切片调用 RunAllTasks
// TODO: 打印 "Main function done"
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Go 在线编译器