当前位置:首页 > 科技  > 软件

Golang 中的 Context 包

来源: 责编: 时间:2023-11-14 09:10:08 209观看
导读今天,我们将讨论 Go 编程中非常重要的一个主题:context 包。如果你现在觉得它很令人困惑,不用担心 — 在本文结束时,你将像专家一样处理 context!想象一下,你在一个主题公园,兴奋地准备搭乘一座巨大的过山车。但有个问题:排队

今天,我们将讨论 Go 编程中非常重要的一个主题:context 包。如果你现在觉得它很令人困惑,不用担心 — 在本文结束时,你将像专家一样处理 context!1N928资讯网——每日最新资讯28at.com

想象一下,你在一个主题公园,兴奋地准备搭乘一座巨大的过山车。但有个问题:排队的人非常多,而且公园快要关门,你只有一个小时的时间。你会怎么办?嗯,你可能会等一会儿,但不会等一个小时,对吧?如果你等了 30 分钟还没有到前面,你会离开队伍去尝试其他游乐设施。这就是我们所谓的 '超时'。1N928资讯网——每日最新资讯28at.com

1N928资讯网——每日最新资讯28at.com

现在,想象一下,你还在排队,突然下起了倾盆大雨。过山车的操作员决定关闭过山车。你不会继续排队等待根本不会发生的事情,对吧?你会立刻离开队伍。这就是我们所谓的 '取消'。1N928资讯网——每日最新资讯28at.com

在编程世界中,我们经常面临类似的情况。我们要求程序执行可能需要很长时间或需要因某种原因停止的任务。这就是 context 包发挥作用的地方。它允许我们优雅地处理这些超时和取消。1N928资讯网——每日最新资讯28at.com

它是如何工作的

(1) 创建上下文:我们首先创建一个上下文。这就像排队等待过山车一样。1N928资讯网——每日最新资讯28at.com

ctx := context.Background() // This gives you an empty context

(2) 设置超时:接下来,我们可以在上下文中设置超时。这就好比你决定在排队多久后放弃并去尝试其他游乐设施。1N928资讯网——每日最新资讯28at.com

ctxWithTimeout, cancel := context.WithTimeout(ctx, time.Second*10) // Wait for 10 seconds// Don't forget to call cancel when you're done, or else you might leak resources!defer cancel()

(3) 检查超时:现在,我们可以使用上下文来检查是否等待时间太长,是否应该停止我们的任务。这就好比在排队等待时看看手表。1N928资讯网——每日最新资讯28at.com

select {case <-time.After(time.Second * 15): // This task takes 15 seconds    fmt.Println("Finished the task")case <-ctxWithTimeout.Done():    fmt.Println("We've waited too long, let's move on!") // We only wait for 10 seconds}

(4) 取消上下文:最后,如果出于某种原因需要停止任务,我们可以取消上下文。这就好比听到因下雨而宣布过山车关闭。1N928资讯网——每日最新资讯28at.com

cancel() // We call the cancel function we got when we created our context with timeout

示例 1:慢速数据库查询

想象一下构建一个从数据库中获取用户数据的Web应用程序。有时,数据库响应较慢,你不希望用户永远等下去。在这种情况下,你可以使用带有超时的上下文。1N928资讯网——每日最新资讯28at.com

func getUser(ctx context.Context, id int) (*User, error) {    // Create a new context that will be cancelled if it takes more than 3 seconds    ctx, cancel := context.WithTimeout(ctx, 3*time.Second)    defer cancel()    // Assume db.QueryRowContext is a function that executes a SQL query and returns a row    row := db.QueryRowContext(ctx, "SELECT name FROM users WHERE id = ?", id)    var name string    if err := row.Scan(&name); err != nil {        return nil, err    }    return &User{Name: name}, nil}

在这个示例中,如果数据库查询花费超过3秒的时间,上下文将被取消,db.QueryRowContext 应返回一个错误。1N928资讯网——每日最新资讯28at.com

示例 2:网页抓取

假设你正在编写一个用于从网站抓取数据的程序。然而,该网站有时响应较慢,或者根本不响应。你可以使用上下文来防止你的程序陷入困境。1N928资讯网——每日最新资讯28at.com

func scrapeWebsite(ctx context.Context, url string) (*html.Node, error) {    // Create a new context that will be cancelled if it takes more than 5 seconds    ctx, cancel := context.WithTimeout(ctx, 5*time.Second)    defer cancel()    // Create a request with the context    req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)    if err != nil {        return nil, err    }    // Execute the request    resp, err := http.DefaultClient.Do(req)    if err != nil {        return nil, err    }    defer resp.Body.Close()    // Parse the response body as HTML    return html.Parse(resp.Body), nill}

在这个示例中,如果从网站获取数据超过5秒,上下文将被取消,http.DefaultClient.Do 应该返回一个错误。1N928资讯网——每日最新资讯28at.com

示例3:长时间运行的任务

假设你有一个执行长时间运行任务的程序,但你希望能够在程序接收到关闭信号时停止任务。这在一个 Web 服务器中可能会很有用,当关闭时必须停止提供请求并进行清理。1N928资讯网——每日最新资讯28at.com

func doTask(ctx context.Context) {    for {        select {        case <-time.After(1 * time.Second):            // The task is done, we're ready to exit            fmt.Println("Task is done")            return        case <-ctx.Done():            // The context was cancelled from the outside, clean up and exit            fmt.Println("Got cancel signal, cleaning up")            return        }    }}func main() {    // Create a new context    ctx, cancel := context.WithCancel(context.Background())    // Start the task in a goroutine    go doTask(ctx)    // Wait for a shutdown signal    <-getShutdownSignal()    // Cancel the context, which will stop the task    cancel()    // Wait for a bit to allow the task to clean up    time.Sleep(1 * time.Second)}

在这个示例中,当程序接收到关闭信号时,它会取消上下文,这会导致 doTask 在 <-ctx.Done() 上接收到信号。1N928资讯网——每日最新资讯28at.com

示例4:HTTP 服务器

假设你正在构建一个处理传入请求的 HTTP 服务器。一些请求可能需要很长时间来处理,你希望设置一个最长处理时间限制。1N928资讯网——每日最新资讯28at.com

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {    ctx, cancel := context.WithTimeout(r.Context(), 2*time.Second)    defer cancel()    // Simulate a long-running operation    select {    case <-time.After(3 * time.Second):        w.Write([]byte("Operation finished."))    case <-ctx.Done():        w.Write([]byte("Operation timed out."))    }})http.ListenAndServe(":8080", nil)

在这个示例中,如果操作需要超过2秒的时间,上下文将被取消,并且服务器将响应“操作超时”。1N928资讯网——每日最新资讯28at.com

示例5:同步多个 Goroutines

假设你正在编写一个程序,使用 Goroutines 并发执行多个任务。如果其中一个任务失败,你希望取消所有其他任务。1N928资讯网——每日最新资讯28at.com

func doTask(ctx context.Context, id int) {    select {    case <-time.After(time.Duration(rand.Intn(4)) * time.Second):        fmt.Printf("Task %v finished./n", id)    case <-ctx.Done():        fmt.Printf("Task %v cancelled./n", id)    }}func main() {    ctx, cancel := context.WithCancel(context.Background())    for i := 1; i <= 5; i++ {        go doTask(ctx, i)    }    // Cancel the context after 2 seconds    time.Sleep(2 * time.Second)    cancel()    // Give the tasks some time to finish up    time.Sleep(1 * time.Second)}

在这个示例中,当上下文被取消时,仍在运行的任何任务都将收到 <-ctx.Done(),从而允许它们进行清理并退出。1N928资讯网——每日最新资讯28at.com

仍然在尝试理解吗?

当我第一次接触上下文时,我感到非常困惑,我提出了一个问题,即如果 select 前面的命令花费太长时间,那么我们永远无法检测到 取消,这是一个合理的问题。因此,我准备了另一个示例来详细解释这种情况。1N928资讯网——每日最新资讯28at.com

package mainimport ( "context" "fmt" "math/rand" "time")func expensiveCalculation(ctx context.Context, resultChan chan<- int) { // Simulate a long-running calculation rand.Seed(time.Now().UnixNano()) sleepTime := time.Duration(rand.Intn(20)+1) * time.Second fmt.Printf("Calculation will take %s to complete/n", sleepTime) time.Sleep(sleepTime) select { case <-ctx.Done():  // Context was cancelled, don't write to the channel  return default:  // Write the result to the channel  resultChan <- 42 // replace with your actual calculation result }}func main() { // Create a context that will be cancelled after 10 seconds ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() // The cancel should be deferred so resources are cleaned up resultChan := make(chan int) // Start the expensive calculation in a separate goroutine go expensiveCalculation(ctx, resultChan) // Wait for either the result or the context to be done select { case res := <-resultChan:  // Got the result  fmt.Printf("Calculation completed with result: %d/n", res) case <-ctx.Done():  // Context was cancelled  fmt.Println("Calculation cancelled") }}

time.Sleep(sleepTime) 命令是阻塞的,将暂停 goroutine 的执行,直到指定的持续时间已过。这意味着 select 语句不会被执行,直到休眠时间已经过去。1N928资讯网——每日最新资讯28at.com

然而,上下文的取消与 goroutine 内的执行是独立的。如果上下文的截止时间被超过或其 cancel() 函数被调用,它的 Done() 通道将被关闭。1N928资讯网——每日最新资讯28at.com

在主 goroutine 中,您有另一个 select 语句,它将立即检测上下文的 Done() 通道是否已关闭,并在不等待 expensiveCalculation goroutine 完成休眠的情况下打印 **"Calculation cancelled"**。1N928资讯网——每日最新资讯28at.com

也就是说,expensiveCalculation goroutine 将在休眠后继续执行,它将在尝试写入 resultChan 之前检查上下文是否已被取消。如果已被取消,它将立即返回。这是为了避免潜在的死锁,如果没有其他goroutine从 resultChan 读取。1N928资讯网——每日最新资讯28at.com

如果需要昂贵的计算(在本例中由 time.Sleep 模拟)在取消时立即停止,您必须设计计算以周期性地检查上下文是否已取消。这通常在需要将计算分解为较小部分的情况下使用循环。如果计算不能分解,并需要一次运行完毕,那么很遗憾,在 Go 中无法提前停止它。1N928资讯网——每日最新资讯28at.com

本文链接://www.dmpip.com//www.dmpip.com/showinfo-26-24320-0.htmlGolang 中的 Context 包

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: C 语言编译器(IDE)初学者指南:选择适合你的工具

下一篇: 使用Python进行文本分析-将PDF文件多进程批量处理为csv文件

标签:
  • 热门焦点
  • 5月iOS设备好评榜:iPhone 14仅排第43?

    5月iOS设备好评榜:iPhone 14仅排第43?

    来到新的一月,安兔兔的各个榜单又重新汇总了数据,像安卓阵营的榜单都有着比较大的变动,不过iOS由于设备的更新换代并没有那么快,所以相对来说变化并不大,特别是iOS好评榜,老款设
  • 一文掌握 Golang 模糊测试(Fuzz Testing)

    一文掌握 Golang 模糊测试(Fuzz Testing)

    模糊测试(Fuzz Testing)模糊测试(Fuzz Testing)是通过向目标系统提供非预期的输入并监视异常结果来发现软件漏洞的方法。可以用来发现应用程序、操作系统和网络协议等中的漏洞或
  • 一个注解实现接口幂等,这样才优雅!

    一个注解实现接口幂等,这样才优雅!

    场景码猿慢病云管理系统中其实高并发的场景不是很多,没有必要每个接口都去考虑并发高的场景,比如添加住院患者的这个接口,具体的业务代码就不贴了,业务伪代码如下:图片上述代码有
  • 拼多多APP上线本地生活入口,群雄逐鹿万亿市场

    拼多多APP上线本地生活入口,群雄逐鹿万亿市场

    Tech星球(微信ID:tech618)文 | 陈桥辉 Tech星球独家获悉,拼多多在其APP内上线了&ldquo;本地生活&rdquo;入口,位置较深,位于首页的&ldquo;充值中心&rdquo;内,目前主要售卖美食相关的
  • 10天营收超1亿美元,《星铁》比《原神》差在哪?

    10天营收超1亿美元,《星铁》比《原神》差在哪?

    来源:伯虎财经作者:陈平安即便你没玩过《原神》,你一定听说过的它的大名。恨它的人把《原神》开服那天称作是中国游戏史上最黑暗的一天,有粉丝因为索尼在PS平台上线《原神》,怒而
  • “又被陈思诚骗了”

    “又被陈思诚骗了”

    作者|张思齐 出品|众面(ID:ZhongMian_ZM)如今的国产悬疑电影,成了陈思诚的天下。最近大爆电影《消失的她》票房突破30亿断层夺魁暑期档,陈思诚再度风头无两。你可以说陈思诚的
  • 华为将推出盘古数字人大模型 可帮助用户12小时完成数字人生成

    华为将推出盘古数字人大模型 可帮助用户12小时完成数字人生成

    在今日举行的2023年华为云数字文娱AI创新峰会上,华为云全球Marketing与销售服务总裁石冀琳表示,华为云将在后续推出盘古数字人大模型,可帮助用户12小
  • iQOO Neo8系列今日官宣:首发天玑9200+ 全球安卓最强芯!

    iQOO Neo8系列今日官宣:首发天玑9200+ 全球安卓最强芯!

    在昨日举行的的联发科新一代旗舰芯片天玑9200+的发布会上,iQOO官方也正式宣布,全新的iQOO Neo8系列新品将全球首发搭载这款当前性能最强大的移动平台
  • 由于成本持续增加,笔记本产品价格预计将明显上涨

    由于成本持续增加,笔记本产品价格预计将明显上涨

    根据知情人士透露,由于材料、物流等成本持续增加,笔记本产品价格预计将在2021年下半年有明显上涨。进入6月下旬以来,全球半导体芯片缺货情况加剧,显卡、处理器
Top
Baidu
map