马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
一、什么是 Goroutine?
Goroutine 是 Golang 中的一种轻量级线程,用于实现并发利用。与传统线程相比,Goroutine 的上风在于它具有更低的资源斲丧和更高的服从。每个 Goroutine 在运行时被 Go 的调理器(Scheduler)管理,而且它们共享内存空间。这使得在单个体系线程上运行成千上万个 Goroutine 成为大概。
1、Goroutine 的特点:
- 轻量级:内存开销非常小,约莫只需 2KB。
- 非抢占式调理:Goroutine 志愿让出 CPU,通过协作完成使命切换。
- 并发与并行:Goroutine 提供并发模子,多个使命可以同时举行。
- 壅闭模子简化开辟:制止了复杂的回调函数,使代码布局更加轻便。
二、怎样启动 Goroutine
要启动 Goroutine,我们只必要在函数调用前加上 go 关键字。此利用会将该函数在单独的 Goroutine 中异步实行,主步调不会期待它完成。
语法:
示例 1:根本的 Goroutine 用法
- package main
- import (
- "fmt"
- "time"
- )
- func printMessage() {
- fmt.Println("Goroutine is running!")
- }
- func main() {
- go printMessage() // 启动 Goroutine
- time.Sleep(1 * time.Second) // 暂停主线程,确保 Goroutine 执行完
- fmt.Println("Main function is done.
- ")
- }
复制代码 输出:
- Goroutine is running!
- Main function is done.
复制代码 表明:
- 主 Goroutine(即 main 函数)立即启动了一个子 Goroutine 来运行 printMessage 函数。
- 假如没有 time.Sleep,主 Goroutine 大概会在子 Goroutine 还未实行时竣事,导致没有输出。
三、主 Goroutine 与子 Goroutine 的关系
- 主 Goroutine:main 函数所在的 Goroutine,步调从这里开始运行。
- 子 Goroutine:由主 Goroutine 或其他 Goroutine 创建的 Goroutine。
关键点:假如主 Goroutine 竣事,全部未完成的子 Goroutine 也会被欺压制止。
示例 2:主线程竣事导致子 Goroutine 制止
- package main
- import (
- "fmt"
- "time"
- )
- func main() {
- go func() {
- time.Sleep(2 * time.Second)
- fmt.Println("This message may never appear.")
- }()
- fmt.Println("Main function is done.
- ")
- // 主 Goroutine 立即结束,子 Goroutine 没有机会完成
- }
复制代码 输出:
表明:
- 主 Goroutine 竣事时,全部未完成的子 Goroutine 会立即制止,因此不会看到子 Goroutine 的输出。
四、Goroutine 的参数通报
在 Golang 中,Goroutine 支持通报参数,但必要留意是按值通报,而不是按引用。
示例 3:Goroutine 通报参数
- package main
- import (
- "fmt"
- )
- func printNumber(num int) {
- fmt.Println("Number:", num)
- }
- func main() {
- for i := 1; i <= 3; i++ {
- go printNumber(i) // 启动 Goroutine 传递参数
- }
- fmt.Scanln() // 等待用户输入,防止程序提前结束
- }
复制代码 输出(大概):
- Number: 1
- Number: 2
- Number: 3
复制代码 五、匿名函数中的变量捕捉题目
Goroutine 常与匿名函数一起利用,但要鉴戒变量捕捉题目。在循环中启动 Goroutine 时,匿名函数大概捕捉的不是当前迭代变量的值,而是循环竣事后的变量。
示例 4:错误的变量捕捉
- package main
- import (
- "fmt"
- "time"
- )
- func main() {
- for i := 1; i <= 3; i++ {
- go func() {
- fmt.Println(i) // 捕获的可能是循环结束后的 i
- }()
- }
- time.Sleep(1 * time.Second)
- }
复制代码 输出:
修改后的代码:将变量作为参数通报
- go func(n int) {
- fmt.Println(n)
- }(i)
复制代码 六、利用 WaitGroup 期待 Goroutine 完成
time.Sleep 不是期待 Goroutine 完成的最佳方式。Go 提供了 sync.WaitGroup 来管理多个 Goroutine 的同步。
示例 5:利用 WaitGroup
- package main
- import (
- "fmt"
- "sync"
- )
- func printMessage(msg string, wg *sync.WaitGroup) {
- defer wg.Done() // Goroutine 完成时调用 Done()
- fmt.Println(msg)
- }
- func main() {
- var wg sync.WaitGroup
- wg.Add(3) // 等待 3 个 Goroutine
- go printMessage("Hello", &wg)
- go printMessage("from", &wg)
- go printMessage("Goroutine!", &wg)
- wg.Wait() // 等待所有 Goroutine 完成
- fmt.Println("All Goroutines are done.")
- }
复制代码 输出:
- Hello
- from
- Goroutine!
- All Goroutines are done.
复制代码 表明:
- wg.Add(n) 体现必要期待 n 个 Goroutine 完成。
- 每个 Goroutine 竣事时调用 wg.Done()。
- wg.Wait() 会壅闭主 Goroutine,直到全部使命完成。
七、Goroutine 的典范应用场景
- I/O 并发:处置惩罚大量网络哀求,镌汰相应时间。
- 配景使命:实行定时使命、日记记录等。
- 并行盘算:分布盘算使命,进步步调性能。
- 定时器与延时利用:如每隔一段时间实行某个利用。
八、留意事项与最佳实践
- 制止死锁:当 Goroutine 期待相互时大概出现死锁,应鉴戒处置惩罚共享资源。
- 公道利用 WaitGroup 和 Channel:确保 Goroutine 的同步与通讯。
- 制止启动过多 Goroutine:固然 Goroutine 轻量,但过多的 Goroutine 也会占用体系资源。
- 调试工具:利用 go tool trace 和 pprof 举行性能调优和调试。
九、小结
Goroutine 是 Golang 的强盛并发工具,其高效、易用的特点让它成为开辟者实现并发步调的首选。在这篇博客中,我们先容了 Goroutine 的底子用法、参数通报和同步机制,并演示了常见的应用场景和留意事项。
在下一篇博客中,我将具体先容 通道(Channel) 的利用,它是 Goroutine 之间举行通讯的重要工具。敬请期待!
|