Go语言面试题:如何使用 Context 控制并发

2023-07-0219:48:32编程语言入门到精通Comments1,121 views字数 1875阅读模式

context的面试题还是比较多,发现context控制并发这块的面试最近出现的频率非常高,所以单独抽出来说说。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/49383.html

一、前言

Go在 1.7 引入了context包,目的是为了在不同的goroutine之间或跨API边界传递超时、取消信号和其他请求范围内的值。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/49383.html

Go 语言中,Context 包是用于传递请求范围数据、取消信号和截止时间的机制。它通常被用来处理 goroutine 之间的通信和取消。Context 包是 Go 语言内置的,它可以很方便地使用,而不需要额外的依赖。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/49383.html

二、并发控制

一般情况下,当一个代码运行完毕后它所在的Goroutine就自动销毁了这并不需要我们认为的去干预些什么,但是当这个程序正处于某种循环下,我们就需要某种命令来打破这个循环。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/49383.html

例如有一个系统监控的Goroutine 设定它每10分钟收集一次系统的数据,那这个肯定是一个无限循环的程序。也就是说只要主Goroutine没问题,电脑没当机,这个Goroutine会一直跑下去。但是我突然不想让他收集但同时我又不想退出主程序,那我该怎么办?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/49383.html

这种时候我们一般有两种方法,一种是channel的方式来发送停止信号。另一种就是使用context(当然接收信号并停止的操作要提前写好)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/49383.html

2.1 channel并发控制

package main
import (  "fmt"    "time")func work(num string, stop chan bool){Loop:  for {    select {    case <- stop:      fmt.Println("任务"+num+" 结束了。。。")      break Loop    default:      fmt.Println(" 任务"+num+" 正在运行中。")      time.Sleep(time.Second * 2)    }  }}func main() {    stop := make(chan bool)    // 开启goroutine    go work("1",stop)    go work("2",stop)    // 运行10s后停止    time.Sleep(time.Second * 10)    fmt.Println("需要停止任务。。。")    stop <- true    time.Sleep(time.Second * 3)}

运行一下会发生什么?会不会同时关闭呢?当然不会,只能关闭一个。因为channel的获取是抢占式的也就是说谁抢到这个channel信号才能进行关闭。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/49383.html

运行结果如下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/49383.html

Go语言面试题:如何使用 Context 控制并发文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/49383.html

2.2 context并发控制

一个典型的使用场景是,当我们需要启动多个 goroutine 进行任务处理时,我们可以使用 Context 来控制这些 goroutine 的执行。在每个 goroutine 中,我们都可以检测 Context 对象是否被取消,如果是,则退出 goroutine 的执行,否则继续执行。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/49383.html

package main
import (  "fmt"    "time"  "context")func work(num string, ctx context.Context){Loop:  for {    select {    case <- ctx.Done():      fmt.Println("任务"+num+" 结束了。。。")      break Loop    default:      fmt.Println(" 任务"+num+" 正在运行中。")      time.Sleep(time.Second * 2)    }  }}
func main() {    ctx, cancel := context.WithCancel(context.Background())    // 开启goroutine    go work("1",ctx)    go work("2",ctx)    // 运行10s后停止    time.Sleep(time.Second * 10)    fmt.Println("需要停止任务。。。")    cancel()    time.Sleep(time.Second * 3)}

在上面的代码中,我们首先使用 context.Background() 函数创建一个根 Context 对象 parent,然后使用 WithCancel 函数创建一个子 Context 对象 ctx,并返回一个取消函数 cancel。在主函数中,我们启动了2个 goroutine 来执行任务,同时使用 cancel 函数来通知这些 goroutine 取消执行。最后执行结果如下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/49383.html

Go语言面试题:如何使用 Context 控制并发文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/49383.html

三、总结

Context 包是 Go 语言中实现并发控制和超时控制的重要工具之一,可以帮助我们更加灵活的控制程序的执行。在实际应用中,我们可以使用 Context 包来实现一些复杂的功能,例如控制数据库连接池、处理 HTTP 请求和 gRPC 请求等。通过使用 Context 包,我们可以更好地实现并发控制和超时控制,提高程序的可靠性和稳定性。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/49383.html

  • 本站内容整理自互联网,仅提供信息存储空间服务,以方便学习之用。如对文章、图片、字体等版权有疑问,请在下方留言,管理员看到后,将第一时间进行处理。
  • 转载请务必保留本文链接:https://www.cainiaoxueyuan.com/ymba/49383.html

Comment

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定