设为首页收藏本站
网站公告 | 这是第一条公告
     

 找回密码
 立即注册
缓存时间18 现在时间18 缓存数据 凭什么要把我教给你的东西,都给下一个女孩子。

凭什么要把我教给你的东西,都给下一个女孩子。 -- 还是分开

查看: 1502|回复: 3

GOLANG使用Context管理关联goroutine的方法

[复制链接]

  离线 

TA的专栏

  • 打卡等级:热心大叔
  • 打卡总天数:234
  • 打卡月天数:0
  • 打卡总奖励:3992
  • 最近打卡:2025-04-23 05:27:37
等级头衔

等級:晓枫资讯-上等兵

在线时间
5 小时

积分成就
威望
0
贡献
470
主题
401
精华
0
金钱
5330
积分
941
注册时间
2023-1-8
最后登录
2025-5-31

发表于 2023-5-2 16:07:38 | 显示全部楼层 |阅读模式
一般一个业务很少不用到goroutine的,因为很多方法是需要等待的,例如
  1. http.Server.ListenAndServe
复制代码
这个就是等待的,除非关闭了Server或Listener,否则是不会返回的。除非是一个API服务器,否则肯定需要另外起goroutine发起其他的服务,而且对于API服务器来说,在
  1. http.Handler
复制代码
的处理函数中一般也需要起goroutine,如何管理这些goroutine,在GOLANG1.7提供
  1. context.Context
复制代码

先看一个简单的,如果启动两个goroutine,一个是HTTP,还有个信号处理的收到退出信号做清理:
  1. wg := sync.WaitGroup{}
  2. defer wg.Wait()

  3. wg.Add(1)
  4. go func() {
  5.   defer wg.Done()

  6.   ss := make(os.Signal, 0)
  7.   signal.Notify(ss, syscall.SIGINT, syscall.SIGTERM)
  8.   for s := ss {
  9.     fmt.Println("Got signal", s)
  10.     break
  11.   }
  12. }()

  13. wg.Add(1)
  14. go func() {
  15.   defer wg.Done()

  16.   svr := &http.Server{ Addr:":8080", Handler:nil, }
  17.   fmt.Println(svr.ListenAndServe())
  18. }
复制代码
很清楚,起了两个goroutine,然后用WaitGroup等待它们退出。如果它们之间没有交互,不互相影响,那真的是蛮简单的,可惜这样是不行的,因为信号的goroutine收到退出信号后,应该通知server退出。暴力一点的是直接调用
  1. svr.Close()
复制代码
,但是如果有些请求还需要取消怎么办呢?最好用Context了:
  1. wg := sync.WaitGroup{}
  2. defer wg.Wait()

  3. ctx,cancel := context.WithCancel(context.Background())

  4. wg.Add(1)
  5. go func() {
  6.   defer wg.Done()

  7.   ss := make(chan os.Signal, 0)
  8.   signal.Notify(ss, syscall.SIGINT, syscall.SIGTERM)
  9.   select {
  10.   case <- ctx.Done():
  11.     return
  12.   case s := <- ss:
  13.     fmt.Println("Got signal", s)
  14.     cancel() // 取消请求,通知用到ctx的所有goroutine
  15.     return
  16.   }
  17. }()

  18. wg.Add(1)
  19. go func() {
  20.   defer wg.Done()
  21.   defer cancel()

  22.   svr := &http.Server{ Addr:":8080", Handler:nil, }

  23.   go func(){
  24.     select {
  25.     case <- ctx.Done():
  26.       svr.Close()
  27.     }
  28.   }

  29.   fmt.Println(svr.ListenAndServe())
  30. }
复制代码
这个方式可以在新开goroutine时继续使用,譬如新加一个goroutine,里面读写了UDPConn:
  1. wg.Add(1)
  2. go func() {
  3.   defer wg.Done()
  4.   defer cancel()

  5.   var conn *net.UDPConn
  6.   if conn,err = net.Dial("udp", "127.0.0.1:1935"); err != nil {
  7.     fmt.Println("Dial UDP server failed, err is", err)
  8.     return
  9.   }

  10.   fmt.Println(UDPRead(ctx, conn))
  11. }()

  12. UDPRead = func(ctx context.Context, conn *net.UDPConn) (err error) {
  13.   wg := sync.WaitGroup{}
  14.   defer wg.Wait()

  15.   ctx, cancel := context.WithCancel(ctx)

  16.   wg.Add(1)
  17.   go func() {
  18.     defer wg.Done()
  19.     defer cancel()

  20.     for {
  21.       b := make([]byte, core.MTUSize)
  22.       size, _, err := conn.ReadFromUDP(b)
  23.       // 处理UDP包 b[:size]
  24.     }
  25.   }()

  26.   select {
  27.   case <-ctx.Done():
  28.     conn.Close()
  29.   }
  30.   return
  31. }
复制代码
如果只是用到HTTP Server,可以这么写:
  1. func run(ctx contex.Context) {
  2.   server := &http.Server{Addr: addr, Handler: nil}
  3.   go func() {
  4.     select {
  5.     case <-ctx.Done():
  6.       server.Close()
  7.     }
  8.   }()

  9.   http.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) {
  10.   })

  11.   fmt.Println(server.ListenAndServe())
  12. }
复制代码
如果需要提供一个API来让服务器退出,可以这么写:
  1. func run(ctx contex.Context) {
  2.   server := &http.Server{Addr: addr, Handler: nil}

  3.   ctx, cancel := context.WithCancel(ctx)
  4.   http.HandleFunc("/quit", func(w http.ResponseWriter, r *http.Request) {
  5.     cancel() // 使用局部的ctx和cancel
  6.   })

  7.   go func() {
  8.     select {
  9.     case <-ctx.Done():
  10.       server.Close()
  11.     }
  12.   }()

  13.   fmt.Println(server.ListenAndServe())
  14. }
复制代码
使用局部的ctx和cancel,可以避免cancel传入的ctx,只是影响当前的ctx。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持晓枫资讯。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
      1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
      2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
      3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:点击这里给我发消息进行删除处理。
      4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
      5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
-4
主题
1
精华
0
金钱
15
积分
21
注册时间
2022-12-24
最后登录
2023-6-14

发表于 2024-1-13 21:04:13 | 显示全部楼层
顶顶更健康!!!
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

  • 打卡等级:无名新人
  • 打卡总天数:1
  • 打卡月天数:0
  • 打卡总奖励:16
  • 最近打卡:2025-01-23 08:22:21
等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
28
积分
4
注册时间
2023-10-27
最后登录
2025-1-23

发表于 2024-9-19 18:51:28 | 显示全部楼层
感谢楼主,顶。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
12
积分
4
注册时间
2023-10-22
最后登录
2023-10-22

发表于 2025-4-20 06:03:54 | 显示全部楼层
感谢楼主分享。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~
严禁发布广告,淫秽、色情、赌博、暴力、凶杀、恐怖、间谍及其他违反国家法律法规的内容。!晓枫资讯-社区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1楼
2楼
3楼
4楼

手机版|晓枫资讯--科技资讯社区 本站已运行

CopyRight © 2022-2025 晓枫资讯--科技资讯社区 ( BBS.yzwlo.com ) . All Rights Reserved .

晓枫资讯--科技资讯社区

本站内容由用户自主分享和转载自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

如有侵权、违反国家法律政策行为,请联系我们,我们会第一时间及时清除和处理! 举报反馈邮箱:点击这里给我发消息

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表