Goroutines 教程
1. 概述
Goroutines 是 Go 语言中实现并发编程的核心机制。它们是轻量级的线程,由 Go 运行时(runtime)管理,允许你在程序中同时执行多个任务。Goroutines 比传统的线程更高效,因为它们的创建和销毁开销很小,并且 Go 运行时会自动处理它们的调度。
2. Goroutines 的基本概念
2.1 什么是 Goroutine?
Goroutine 是一个函数或方法的执行实例,它与其他 Goroutines 并发运行。你可以将 Goroutine 看作是 Go 语言中的“轻量级线程”。
2.2 如何创建 Goroutine?
在 Go 中,你可以通过在函数调用前加上 go 关键字来创建一个 Goroutine。例如:
package main
import (
"fmt"
"time"
)
func printNumbers() {
for i := 1; i <= 5; i++ {
fmt.Println(i)
time.Sleep(time.Millisecond * 500)
}
}
func printLetters() {
for i := 'a'; i <= 'e'; i++ {
fmt.Printf("%c\n", i)
time.Sleep(time.Millisecond * 500)
}
}
func main() {
go printNumbers() // 创建一个 Goroutine 来执行 printNumbers 函数
go printLetters() // 创建另一个 Goroutine 来执行 printLetters 函数
// 主 Goroutine 等待一段时间,以便其他 Goroutines 有足够的时间执行
time.Sleep(time.Second * 3)
}
在这个例子中,printNumbers 和 printLetters 函数分别在两个不同的 Goroutines 中并发执行。主 Goroutine 通过 time.Sleep 等待一段时间,以确保其他 Goroutines 有足够的时间完成执行。
2.3 Goroutines 的调度
Go 运行时使用一种称为 M:N 调度的机制,其中 M 个 Goroutines 被映射到 N 个操作系统线程上。这意味着 Go 运行时可以高效地管理大量的 Goroutines,而不会消耗过多的系统资源。
3. 实践练习
3.1 练习:并发计算
编写一个程序,使用 Goroutines 并行计算一组数字的平方和立方。
package main
import (
"fmt"
"sync"
)
func square(num int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("Square of %d is %d\n", num, num*num)
}
func cube(num int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("Cube of %d is %d\n", num, num*num*num)
}
func main() {
var wg sync.WaitGroup
numbers := []int{1, 2, 3, 4, 5}
for _, num := range numbers {
wg.Add(2)
go square(num, &wg)
go cube(num, &wg)
}
wg.Wait()
}
在这个练习中,我们使用了 sync.WaitGroup 来等待所有的 Goroutines 完成执行。每个数字的平方和立方计算都在不同的 Goroutines 中并发执行。
3.2 练习:并发下载
编写一个程序,使用 Goroutines 并发下载多个文件。
package main
import (
"fmt"
"io"
"net/http"
"os"
"sync"
)
func downloadFile(url string, wg *sync.WaitGroup) {
defer wg.Done()
resp, err := http.Get(url)
if err != nil {
fmt.Println("Error downloading", url, ":", err)
return
}
defer resp.Body.Close()
out, err := os.Create(url[strings.LastIndex(url, "/")+1:])
if err != nil {
fmt.Println("Error creating file:", err)
return
}
defer out.Close()
_, err = io.Copy(out, resp.Body)
if err != nil {
fmt.Println("Error writing file:", err)
}
}
func main() {
var wg sync.WaitGroup
urls := []string{
"https://example.com/file1.txt",
"https://example.com/file2.txt",
"https://example.com/file3.txt",
}
for _, url := range urls {
wg.Add(1)
go downloadFile(url, &wg)
}
wg.Wait()
}
在这个练习中,我们使用 Goroutines 并发下载多个文件。每个文件的下载任务都在不同的 Goroutine 中执行,从而提高了下载效率。
4. 总结
Goroutines 是 Go 语言中实现并发编程的强大工具。通过使用 go 关键字,你可以轻松地创建并发任务,并利用 Go 运行时的调度机制来高效地管理这些任务。通过实践练习,你可以更好地理解如何使用 Goroutines 来解决实际问题。
在接下来的课程中,我们将学习如何使用 Channels 和 Select 语句来进一步控制 Goroutines 之间的通信和同步。