golang中context使用小结

 更新时间:2023年11月14日 15:58:24   作者:祥仔先生  
本文主要介绍了golang中context使用小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

一、context使用注意事项

在使用context时,有一些需要注意的事项,以及一些与性能优化相关的建议:

  • 避免滥用context传递数据:context的主要目的是传递请求范围的数据和取消信号,而不是用于传递全局状态或大量数据。滥用context传递大量数据可能导致上下文对象变得臃肿,增加内存和GC压力。

  • 不要修改已传递的context:传递的context是不可变的,即使在函数内部对其调用cancel方法也不会影响调用方的context。如果需要对context进行修改,应该通过返回一个新的派生context来实现。

  • 只在需要时传递context:不要将context作为函数参数无限制地传递,而是在需要时传递。这样可以避免不必要的复杂性和代码膨胀。

  • 及早检查取消信号:在使用context的地方,应该及早检查ctx.Done()的返回值,以尽早响应取消信号。在耗时操作前或可能阻塞的地方,应该通过select语句来监听多个操作,包括取消信号、超时和其他channel。

  • 使用WithCancel替代WithTimeout:在可能的情况下,优先使用WithCancel函数来设置取消信号,而不是仅仅依赖于WithTimeout函数。这样可以有更精确的控制和更灵活的处理方式。

  • 优化context的传递:在频繁调用的函数链中,避免在每个函数中重复传递相同的context,可以通过使用结构体或函数闭包将context作为参数进行传递,从而减少代码重复和提升性能。

  • 及时取消不再需要的goroutine:如果在多个goroutine中使用context,确保在不再需要时及时取消goroutine,以避免资源浪费和潜在的goroutine泄漏。

这些注意事项和性能优化建议可帮助确保正确且高效地使用context,避免滥用和性能问题。根据具体场景和需求,可以灵活使用context的机制来优化代码的可读性、并发安全性和性能。

二、context使用举例

在Go语言中,context(上下文)是在不同goroutine之间传递请求范围数据、取消信号和超时处理的一种机制。下面详细介绍context的每种使用情况和相应的代码举例:

  • 传递请求范围数据:

    package main
    
    import (
    	"context"
    	"fmt"
    )
    
    // 定义一个键类型(key)用于context中的数据传递
    type key string
    
    // 在context中设置数据
    func withValue(ctx context.Context) {
    	// 使用WithValue将数据存储在context中
    	ctxWithData := context.WithValue(ctx, key("name"), "John")
    
    	// 调用另一个函数,并将带有数据的context传递给它
    	printName(ctxWithData)
    }
    
    // 从context中获取并使用数据
    func printName(ctx context.Context) {
    	// 从context中获取数据,并进行类型断言
    	if name, ok := ctx.Value(key("name")).(string); ok {
    		fmt.Println("Name:", name)
    	}
    }
    
    func main() {
    	// 创建根context
    	ctx := context.Background()
    
    	// 传递context并设置数据
    	withValue(ctx)
    }
    

    在上面的示例中,我们定义了一个key类型,用于在context中存储数据。然后,我们使用WithValue函数将数据存储在带有数据的context ctxWithData 中,并将其传递给printName函数。在printName函数中,我们使用Value方法从context中获取数据,并进行类型断言后打印出来。

  • 取消信号:

    package main
    
    import (
    	"context"
    	"fmt"
    	"time"
    )
    
    // 模拟一些耗时操作
    func performTask(ctx context.Context) {
    	// 检查是否接收到取消信号
    	select {
    	case <-ctx.Done():
    		fmt.Println("Task canceled")
    		return
    	default:
    		// 模拟长时间运行的任务
    		time.Sleep(5 * time.Second)
    		fmt.Println("Task completed")
    	}
    }
    
    func main() {
    	// 创建根context
    	ctx := context.Background()
    
    	// 派生子context,并设置取消信号
    	ctx, cancel := context.WithCancel(ctx)
    
    	// 启动耗时操作的goroutine,并传递带有取消信号的context
    	go performTask(ctx)
    
    	// 模拟一些操作后取消任务
    	time.Sleep(2 * time.Second)
    	cancel() // 发送取消信号
    
    	// 等待一段时间,确保程序有足够的时间处理取消信号
    	time.Sleep(1 * time.Second)
    }
    

    在上面的示例中,我们创建了一个任务函数performTask,该函数会检查是否接收到取消信号。使用context.WithCancel函数创建派生的子context,并通过调用返回的cancel函数发送取消信号。然后,我们在一个goroutine中运行任务函数,并通过传递带有取消信号的context来监听取消信号。在主goroutine中,我们等待一段时间后调用cancel函数发送取消信号。当任务函数接收到取消信号后,它会打印"Task canceled"。

  • 超时处理:

    package main
    
    import (
    	"context"
    	"fmt"
    	"time"
    )
    
    // 模拟一些耗时操作
    func performTask(ctx context.Context) {
    	// 检查是否接收到取消信号或超时
    	select {
    	case <-ctx.Done():
    		fmt.Println("Task canceled")
    	case <-time.After(5 * time.Second):
    		fmt.Println("Task completed")
    	}
    }
    
    func main() {
    	// 创建根context
    	ctx := context.Background()
    
    	// 派生子context,并设置超时时间
    	ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
    	defer cancel()
    
    	// 启动耗时操作的goroutine,并传递带有超时设置的context
    	go performTask(ctx)
    
    	// 等待一段时间,确保程序有足够的时间处理超时或取消信号
    	time.Sleep(5 * time.Second)
    }
    

    在上面的示例中,我们创建了一个任务函数performTask,该函数会检查是否接收到取消信号或超时。使用context.WithTimeout函数创建派生的子context,并通过调用返回的cancel函数来设置超时时间。然后,我们在一个goroutine中运行任务函数,并传递带有超时设置的context来监听超时或取消信号。在主goroutine中,我们等待一段时间以确保程序有足够的时间处理超时或取消信号。当超过超时时间后,任务函数会打印"Task canceled"。

这些是context在Go语言中的常见用法,它们使得在并发环境中处理请求范围数据、取消信号和超时变得更加简单和可靠。根据具体的使用场景,你可以选择适当的context函数来创建和传递context,并根据需要进行取消和超时处理。

到此这篇关于golang中context使用小结的文章就介绍到这了,更多相关golang context 内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Go语言使用字符串的几个技巧分享

    Go语言使用字符串的几个技巧分享

    这篇文章中小编将给出一些Go语言在处理字符串方面的技巧,对大家学习Go语言具有一定的参考借鉴价值,下面一起看看吧。
    2016-09-09
  • 浅析go逆向符号恢复

    浅析go逆向符号恢复

    这篇文章主要介绍了go逆向符号恢复的相关知识,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-08-08
  • 初步解读Golang中的接口相关编写方法

    初步解读Golang中的接口相关编写方法

    这篇文章主要介绍了Golang中的接口相关编写方法,是Go语言入门学习中的基础知识,需要的朋友可以参考下
    2015-11-11
  • GO语言中Chan实现原理的示例详解

    GO语言中Chan实现原理的示例详解

    这篇文章主要为大家详细介绍了Go语言中Chan实现原理的相关资料,文中的示例代码讲解详细,对我们学习Go语言有一定的帮助,需要的可以参考一下
    2023-02-02
  • 详解Golang 推荐的命名规范

    详解Golang 推荐的命名规范

    这篇文章主要介绍了详解Golang 推荐的命名规范,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-02-02
  • 一文带你了解Go语言实现的并发神库conc

    一文带你了解Go语言实现的并发神库conc

    前几天逛github发现了一个有趣的并发库-conc,这篇文章将为大家详细介绍一下这个库的实现,文中的示例代码讲解详细,感兴趣的可以了解一下
    2023-01-01
  • Go语言学习之条件语句使用详解

    Go语言学习之条件语句使用详解

    这篇文章主要介绍了Go语言中条件语句的使用,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-04-04
  • go语言中context的使用说明

    go语言中context的使用说明

    Go语言中的Context是用于在多个函数或goroutine之间传递取消信号、超时控制、截止时间和请求范围数据的重要概念,它提供了更好的控制和管理,适用于并发编程中需要传递状态或进行资源清理的场景
    2024-12-12
  • Go语言扩展原语之Semaphore的用法详解

    Go语言扩展原语之Semaphore的用法详解

    Go语言的扩展包中提供了带权重的信号量 semaphore.Weighted,让我们可以按照不同的权重管理资源的访问,下面小编就来和大家聊聊它们的具体用法吧
    2023-07-07
  • Go语言并发技术详解

    Go语言并发技术详解

    这篇文章主要介绍了Go语言并发技术详解,本文讲解了goroutine、channels、Buffered Channels、Range和Close等内容,需要的朋友可以参考下
    2014-10-10

最新评论