go怎么终止协程的运行

devtools/2025/1/8 19:07:51/

在Go语言中,**协程(goroutine)**是由Go的运行时(runtime)管理的轻量级线程。一旦启动,协程会持续运行直到它执行完毕或发生异常。Go语言本身没有显式的“停止”或“关闭”协程的机制,协程的生命周期是由它的代码逻辑决定的。当协程的函数执行完毕时,协程会自动退出。

然而,通常我们希望能够控制终止协程的运行,特别是在协程正在执行某些任务时,可能需要强制停止它。虽然Go没有提供直接的协程终止命令,但可以通过一些机制来间接实现协程的“关闭”。

常见的方式来终止或关闭协程

1. 使用 channel 来通知协程退出

最常见的方式是使用 channel 来传递终止信号。主协程可以向一个专用的退出通道发送信号,通知协程停止。

package mainimport ("fmt""time"
)func worker(done chan bool) {for {select {case <-done:// 收到退出信号,退出协程fmt.Println("Worker is stopping.")returndefault:// 执行任务fmt.Println("Worker is working...")time.Sleep(500 * time.Millisecond)}}
}func main() {done := make(chan bool)go worker(done)// 等待一段时间后,发出停止信号time.Sleep(2 * time.Second)done <- true // 向done channel发送停止信号
}

解释

  • 主协程通过done channel向worker协程发送停止信号。
  • worker协程通过select语句监听done channel,当接收到停止信号时退出。

这种方式是一种协作型的关闭方式,协程本身负责在接收到停止信号后适当清理资源并退出。

2. 使用 context 控制协程

context 包提供了取消、超时和截止时间的控制机制,适用于在协程之间传递取消信号。

package mainimport ("context""fmt""time"
)func worker(ctx context.Context) {for {select {case <-ctx.Done():// 收到取消信号fmt.Println("Worker is stopping due to context cancellation.")returndefault:// 执行任务fmt.Println("Worker is working...")time.Sleep(500 * time.Millisecond)}}
}func main() {// 创建带取消信号的上下文ctx, cancel := context.WithCancel(context.Background())go worker(ctx)// 等待2秒后取消协程time.Sleep(2 * time.Second)cancel() // 发送取消信号
}

解释

  • context.WithCancel 创建一个可取消的上下文 ctx
  • 主协程调用 cancel() 来取消上下文,worker协程会接收到取消信号并退出。

这种方法特别适合在多个协程之间传递取消信号。context可以用来处理超时、取消和截止时间等。

3. 使用 sync.WaitGroup 等待协程完成

sync.WaitGroup 主要用于等待多个协程完成任务,但也可以确保协程安全退出,防止主协程在子协程未完成时就提前退出。

package mainimport ("fmt""sync""time"
)func worker(wg *sync.WaitGroup) {defer wg.Done() // 通知 WaitGroup 当前协程已经完成for i := 0; i < 5; i++ {fmt.Println("Worker is working...")time.Sleep(500 * time.Millisecond)}
}func main() {var wg sync.WaitGroupwg.Add(1) // 启动一个协程go worker(&wg)// 等待协程完成wg.Wait()fmt.Println("Worker has finished.")
}

解释

  • sync.WaitGroup 用来等待协程完成,调用Add(1)增加计数,Done()会减少计数,Wait()会阻塞等待所有计数归零。
  • 这种方式并不直接停止协程,但确保主程序在协程结束前不会退出。
4. 使用 time.After 实现超时控制

time.After可以用来控制协程的超时行为,当时间到达时,它会向channel发送信号。

package mainimport ("fmt""time"
)func worker(done chan bool) {for {select {case <-done:fmt.Println("Worker is stopping.")returndefault:fmt.Println("Worker is working...")time.Sleep(500 * time.Millisecond)}}
}func main() {done := make(chan bool)go worker(done)// 使用time.After来控制协程的超时select {case <-time.After(2 * time.Second): // 2秒后自动停止done <- true}
}

解释

  • time.After(2 * time.Second) 会在2秒后向 done 通道发送信号,从而通知协程退出。
  • 这适用于控制协程的最大执行时间,防止协程执行时间过长。

总结

  • 停止协程的最佳实践:Go没有提供强制停止协程的机制。通常,我们使用 channelcontext 来通知协程退出。
  • channel:适用于明确通知协程退出,通常用于协程之间的通信。
  • context:适用于传递取消信号,尤其是跨多个协程或者多个模块时。
  • sync.WaitGroup:用于等待协程的完成,确保主程序在协程执行完毕后再退出。
  • time.After:适用于设定超时机制,防止协程无限制运行。

http://www.ppmy.cn/devtools/148970.html

相关文章

C 实现植物大战僵尸(三)

C 实现植物大战僵尸&#xff08;三&#xff09; 十 实现豌豆子弹 原设计 这里的设计思路和原 UP 主思路差异比较大&#xff0c;罗列如下 原作中只要僵尸在出现在某条道路上&#xff0c;且存在豌豆射手&#xff0c;豌豆射手就会发射子弹&#xff0c;&#xff08;这里是网页在…

人工智能AI学习路径

一、打好基础 1. 数学基础 - 线性代数&#xff1a;这是 AI 的基石之一。矩阵和向量的运算在神经网络等许多 AI 算法中无处不在。例如&#xff0c;在深度学习中&#xff0c;图像可以被表示为一个矩阵&#xff0c;通过矩阵乘法等操作进行特征提取。你需要理解矩阵的基本运算&…

(安卓无线调试)ADB 无法连接及 Scrcpy 问题排查指南

问题描述 在使用 ADB 和 Scrcpy 时遇到以下问题&#xff1a; 无法连接到 ADB 服务。 即使连接成功&#xff0c;Scrcpy 显示以下错误&#xff1a; INFO: scrcpy 1.10 <https://github.com/Genymobile/scrcpy> D:\.....\scrcpy\scrcpy-server.jar: 1 file pushed. 0.2 …

30分钟学会HTML

HTML 基本语法 HTML&#xff08;HyperText Markup Language&#xff09;是构成网页内容的基础。它使用一系列的标签来描述网页的结构&#xff0c;包括文本、图片、链接等元素。浏览器会解析这些标签并渲染成我们看到的网页。 在线体验一下 CodePen (在线 HTML 编辑器)。 千万不…

H5通过URL Scheme唤醒手机地图APP

1.高德地图 安卓URL Scheme&#xff1a;baidumap:// 官方文档&#xff1a;https://lbs.amap.com/api/amap-mobile/guide/android/navigation IOS URL Scheme&#xff1a;iosamap:// 官方文档&#xff1a;https://lbs.amap.com/api/amap-mobile/guide/ios/navi HarmonyOS NEXT U…

Unity自定义编辑器:基于枚举类型动态显示属性

1.参考链接 2.应用 target并设置多选编辑 添加[CanEditMultipleObjects] using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor;[CustomEditor(typeof(LightsState))] [CanEditMultipleObjects] public class TestInspector :…

C语言——字符函数和内存函数

目录 前言 字符函数 1strlen 模拟实现 2strcpy 模拟实现 3strcat 模拟实现 4strcmp 模拟实现 5strncpy 模拟实现 6strncat 模拟实现 7strncmp 模拟实现 8strstr 模拟实现 9strtok 10strerror 11大小写字符转换函数 内存函数 1memcpy 模拟实现 2…

什么是 ERP?

目录 企业资源计划&#xff08;ERP&#xff09;的定义 ERP与财务管理的区别 ERP基础知识 ERP的业务价值 ERP简史 ERP部署模式&#xff1a;从本地部署到云端 ERP云 — 新的ERP交付模式 迁移至ERP云技术解决方案的7个原因 企业资源计划&#xff08;ERP&#xff09;的定义 …