Go 的并发模型改变了游戏规则,但管理复杂的并发操作可能很棘手。这就是上下文传播和取消的用武之地。这些强大的工具让我们能够构建健壮的、可取消的操作,跨越多个 goroutine 甚至网络边界。
让我们从基础开始。 context 包提供了一种跨 API 边界和进程之间携带截止日期、取消信号和请求范围值的方法。这是控制长时间运行的操作和优雅地关闭服务的秘密武器。
这是一个使用上下文进行取消的简单示例:
func longRunningOperation(ctx context.Context) error { for { select { case <p>在此示例中,我们创建一个超时时间为 5 秒的上下文。如果操作未在该时间内完成,则会自动取消。</p> <p>但是上下文不仅仅适用于超时。我们可以使用它在多个 goroutine 之间传播取消信号。这对于管理复杂的工作流程非常有用。</p> <p>考虑一个我们正在构建分布式事务系统的场景。我们可能在单个事务中涉及多个微服务,我们需要确保如果任何部分失败,整个事务都会回滚。</p> <p>以下是我们如何使用上下文来构建它:<br> </p> <pre class="brush:php;toolbar:false">func performTransaction(ctx context.Context) error { // Start the transaction tx, err := db.BeginTx(ctx, nil) if err != nil { return err } defer tx.Rollback() // Will be no-op if tx.Commit() is called // Perform multiple operations if err := operation1(ctx); err != nil { return err } if err := operation2(ctx); err != nil { return err } if err := operation3(ctx); err != nil { return err } // If we've made it this far, commit the transaction return tx.Commit() } func operation1(ctx context.Context) error { // Make an HTTP request to another service req, err := http.NewRequestWithContext(ctx, "GET", "http://service1.example.com", nil) if err != nil { return err } resp, err := http.DefaultClient.Do(req) if err != nil { return err } defer resp.Body.Close() // Process the response... return nil }
在此示例中,我们使用上下文在数据库操作和 HTTP 请求之间传播取消。如果上下文在任何时候被取消(由于超时或显式取消),所有操作都将终止,并且资源将被清理。
但是如果我们需要对取消进行更细粒度的控制怎么办?这就是自定义上下文类型的用武之地。我们可以创建自己的上下文类型来携带特定于域的取消信号。
这是带有“优先级”值的自定义上下文的示例:
type priorityKey struct{} func WithPriority(ctx context.Context, priority int) context.Context { return context.WithValue(ctx, priorityKey{}, priority) } func GetPriority(ctx context.Context) (int, bool) { priority, ok := ctx.Value(priorityKey{}).(int) return priority, ok } func priorityAwareOperation(ctx context.Context) error { priority, ok := GetPriority(ctx) if !ok { priority = 0 // Default priority } // Use the priority to make decisions... switch priority { case 1: // High priority operation case 2: // Medium priority operation default: // Low priority operation } return nil }
此自定义上下文允许我们传播优先级信息以及取消信号,从而使我们能够更好地控制并发操作。
现在,我们来谈谈优雅关闭。当我们构建长期运行的服务时,正确处理关闭信号至关重要,以确保我们不会留下任何挂起的操作或未清理的资源。
以下是我们如何使用上下文实现正常关闭:
func main() { // Create a context that's cancelled when we receive an interrupt signal ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt) defer cancel() // Start our main service loop errChan := make(chan error, 1) go func() { errChan <p>此设置可确保我们的服务在收到中断信号时可以正常关闭,从而有时间清理资源并完成任何正在进行的操作。</p> <p>Go 上下文系统最强大的方面之一是它能够跨网络边界传播取消。这在构建操作可能跨越多个服务的分布式系统时特别有用。</p><p>让我们看一个如何在微服务架构中实现这一点的示例:<br> </p> <pre class="brush:php;toolbar:false">func longRunningOperation(ctx context.Context) error { for { select { case <p>在此示例中,我们将根据查询参数创建一个带有超时的上下文。然后,该上下文将通过所有后续 API 调用进行传播。如果达到超时,所有正在进行的操作都会被取消,并向客户端返回一个错误。</p> <p>这种模式确保我们不会有任何在客户端放弃等待响应后仍持续很长时间的“失控”操作。它是构建响应迅速、资源高效的分布式系统的关键部分。</p> <p>并发系统中的错误处理可能很棘手,但上下文也可以提供帮助。通过使用上下文,我们可以确保错误正确传播,并且即使发生错误也能清理资源。</p> <p>以下是我们如何处理并发操作中的错误的示例:<br> </p> <pre class="brush:php;toolbar:false">func performTransaction(ctx context.Context) error { // Start the transaction tx, err := db.BeginTx(ctx, nil) if err != nil { return err } defer tx.Rollback() // Will be no-op if tx.Commit() is called // Perform multiple operations if err := operation1(ctx); err != nil { return err } if err := operation2(ctx); err != nil { return err } if err := operation3(ctx); err != nil { return err } // If we've made it this far, commit the transaction return tx.Commit() } func operation1(ctx context.Context) error { // Make an HTTP request to another service req, err := http.NewRequestWithContext(ctx, "GET", "http://service1.example.com", nil) if err != nil { return err } resp, err := http.DefaultClient.Do(req) if err != nil { return err } defer resp.Body.Close() // Process the response... return nil }
在此示例中,我们使用通道将错误从 goroutine 传回 main 函数。我们还在检查取消的上下文。这确保我们能够处理来自操作本身的错误和来自上下文的取消。
上下文的一个经常被忽视的方面是它携带请求范围值的能力。这对于跨 API 边界传播请求 ID、身份验证令牌或其他元数据等内容非常有用。
这是我们如何使用它的示例:
type priorityKey struct{} func WithPriority(ctx context.Context, priority int) context.Context { return context.WithValue(ctx, priorityKey{}, priority) } func GetPriority(ctx context.Context) (int, bool) { priority, ok := ctx.Value(priorityKey{}).(int) return priority, ok } func priorityAwareOperation(ctx context.Context) error { priority, ok := GetPriority(ctx) if !ok { priority = 0 // Default priority } // Use the priority to make decisions... switch priority { case 1: // High priority operation case 2: // Medium priority operation default: // Low priority operation } return nil }
在此示例中,我们使用中间件将请求 ID 添加到上下文。然后可以检索此请求 ID 并在接收此上下文的任何后续处理程序或函数中使用。
在我们结束时,值得注意的是,虽然上下文是一个强大的工具,但它并不是灵丹妙药。过度使用上下文可能会导致代码难以理解和维护。明智地使用上下文并仔细设计 API 非常重要。
请记住,上下文的主要用途应该是跨 API 边界携带截止日期、取消信号和请求范围的值。它并不意味着成为将可选参数传递给函数的通用机制。
总之,掌握 Go 的并发模型(包括上下文传播和取消)是构建健壮、高效且可扩展的应用程序的关键。通过利用这些工具,我们可以创建能够优雅地处理复杂工作流程、有效管理资源并智能地响应不断变化的条件的系统。随着我们不断突破并发编程的极限,这些技术在我们的工具箱中将变得更加重要。
我们的创作
一定要看看我们的创作:
投资者中心 | 智能生活 | 时代与回响 | 令人费解的谜团 | 印度教 | 精英开发 | JS学校
我们在媒体上
科技考拉洞察 | 时代与回响世界 | 投资者中央媒体 | 令人费解的谜团 | 科学与时代媒介 | 现代印度教
以上是Go 大师的并发:上下文传播和取消的秘密揭晓的详细内容。更多信息请关注PHP中文网其他相关文章!

掌握Go语言中的strings包可以提高文本处理能力和开发效率。1)使用Contains函数检查子字符串,2)用Index函数查找子字符串位置,3)Join函数高效拼接字符串切片,4)Replace函数替换子字符串。注意避免常见错误,如未检查空字符串和大字符串操作性能问题。

你应该关心Go语言中的strings包,因为它能简化字符串操作,使代码更清晰高效。1)使用strings.Join高效拼接字符串;2)用strings.Fields按空白符分割字符串;3)通过strings.Index和strings.LastIndex查找子串位置;4)用strings.ReplaceAll进行字符串替换;5)利用strings.Builder进行高效字符串拼接;6)始终验证输入以避免意外结果。

thestringspackageingoisesential forefficientstringManipulation.1)itoffersSimpleyetpoperfulfunctionsFortaskSlikeCheckingSslingSubstringsStringStringsStringsandStringsN.2)ithandhishiCodeDewell,withFunctionsLikestrings.fieldsfieldsfieldsfordsforeflikester.fieldsfordsforwhitespace-fieldsforwhitespace-separatedvalues.3)3)

WhendecidingbetweenGo'sbytespackageandstringspackage,usebytes.Bufferforbinarydataandstrings.Builderforstringoperations.1)Usebytes.Bufferforworkingwithbyteslices,binarydata,appendingdifferentdatatypes,andwritingtoio.Writer.2)Usestrings.Builderforstrin

Go的strings包提供了多种字符串操作功能。1)使用strings.Contains检查子字符串。2)用strings.Split将字符串分割成子字符串切片。3)通过strings.Join合并字符串。4)用strings.TrimSpace或strings.Trim去除字符串首尾的空白或指定字符。5)用strings.ReplaceAll替换所有指定子字符串。6)使用strings.HasPrefix或strings.HasSuffix检查字符串的前缀或后缀。

使用Go语言的strings包可以提升代码质量。1)使用strings.Join()优雅地连接字符串数组,避免性能开销。2)结合strings.Split()和strings.Contains()处理文本,注意大小写敏感问题。3)避免滥用strings.Replace(),考虑使用正则表达式进行大量替换。4)使用strings.Builder提高频繁拼接字符串的性能。

Go的bytes包提供了多种实用的函数来处理字节切片。1.bytes.Contains用于检查字节切片是否包含特定序列。2.bytes.Split用于将字节切片分割成smallerpieces。3.bytes.Join用于将多个字节切片连接成一个。4.bytes.TrimSpace用于去除字节切片的前后空白。5.bytes.Equal用于比较两个字节切片是否相等。6.bytes.Index用于查找子切片在largerslice中的起始索引。

theEncoding/binarypackageingoisesenebecapeitProvidesAstandArdArdArdArdArdArdArdArdAndWriteBinaryData,确保Cross-cross-platformCompatibilitiational and handhandlingdifferentendenness.itoffersfunctionslikeread,写下,写,dearte,readuvarint,andwriteuvarint,andWriteuvarIntforPreciseControloverBinary


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

mPDF
mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

SublimeText3汉化版
中文版,非常好用

WebStorm Mac版
好用的JavaScript开发工具

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver Mac版
视觉化网页开发工具