Go实用技巧

Golang实用技巧

  • Golang实用技巧
    • Context
      • 1. 为了gorouines更可靠,避免实用context.Background()
      • 2. 不幸得是,context.Value 不是我们的朋友
      • 3. 使用context.WithoutCancel 保持 context 活跃

Context

1. 为了gorouines更可靠,避免实用context.Background()

在我们同时管理多个任务时,我们会实用goroutine,对吧?每个goroutine专用于特定的功能,比如发HTTP请求或者查询数据库。当这些任务需要暂停时,问题就出现了,这也是棘手的地方。因为我们不希望goroutines永久停止或阻塞,没有办法退出。

“为什么我们应该避免直接使用 context.Background() ?”

我们之所以避免直接使用 context.Background(),主要是因为它无法在出现问题时停止或取消执行。它是我们能用context的最简单形式,没有值(values) 、没有截止日期(截止日期)、没有取消信号(cancellation signals)。当执行卡住或要顺利结束时,这可能会成为一个问题。

为了解决这个问题,通常我们依靠两个策略:取消(cancel)和超时(timeout):

context.WithTimeout(ctx, duration)
context.WithTimeoutCause(ctx, duration, errors.New("custom message"))context.WithCancel(ctx)
context.WithCancelCause(ctx)context.WithDeadline(ctx)
context.WithDeadlineCause(ctx, deadline, errors.New("custom message"))

有了这些工具,我们启动每个 goroutine 都带有明确的预期:“goroutine可以及时完成任务或者解释为什么不能及时完成,另外必要情况下可以取消任务。”

以下几点请记住:

  • WithTimeout 其实就是换了个名字的 WithDeadline。
  • 最近更新的 Go(版本 1.20 和 1.21)中添加的 XXXCause 函数提供了更好的错误报告。
  • 如果 XXXCause 发生超时,它会提供更详细的错误消息:“context deadline exceeded: custom message.

“channels怎么样?我不想在channel上永久等待。”

为了确保不会无限等待处理channels,更好的管理方法是使用 select 语句,它允许我们设置超时选项:

select{case result := <-ch:fmt.Println("Received result:", result)case <-time.After(5*time.Second):fmt.Println("Timed out")
}

不过需要注意:使用 time.After 可能会导致短期内存泄露。在某些情况下,使用time.Timer 或 time.Ticker 可能更有效,因为它们能让我们更好地控制时间。

译者补充:关于 time.After 可能导致内存泄露的文章,可参考学习:

  1. [golang]golang time.After使用不当导致内存泄露问题分析 - luoming1224 - 博客园 (cnblogs.com)
  2. Go坑:time.After可能导致的内存泄露问题分析 - 九卷 - 博客园 (cnblogs.com)

本文将在接下来技巧中深入探讨替代方案及其价值。

2. 不幸得是,context.Value 不是我们的朋友

context.Value 似乎是一个方便的工具,因为它可以在 context 中携带一些数据,然后在需要的地方取出这些数据。

这会让我们的函数签名简介明了,不是吗?典型的例子是这样的:

func A(ctx context.Context, transactionID string){payment := db.GetPayment(ctx, transactionID)ctx := context.WithValue(ctx, "payment", payment)B(ctx)
}func B(ctx context.Context){...C(ctx)
}func C(ctx context.Context){payment, ok := ctx.Value("payment").(payment)...
}

在这段代码中,函数 A 获取付款记录并将其添加到 context 中, 在 B 内调用的函数 C 检索此付款。这种方法避免直接通过函数 B 传递付款记录,该函数不需要了解付款。

此方法看起来不错,因为:

  • 允许我们省略函数传递特定不使用的数据,就像 B 函数一样。
  • 允许将必要的数据保存在 context 中。
  • 避免函数签名中的额外参数。

为什么不在函数中 A 中直接调用函数 C 呢?通常情况下,C与B的逻辑结合得很深,可能依赖它的某些计算和参数。

那么问题出在哪里呢?问题就出在这里:

  • 放弃了Go在编译过程中提供的类型检查安全性。
  • 我们将数据放入黑匣子中并希望以后能再找到它,而一周之后可能就像盲人搜索一样。
  • 由于隐士传递,付款数据似乎可有可无,但实际上非常重要。

从个人角度来看,使用 ctx.Value 的主要问题在于它如何隐藏数据。这就像把东西放在一个没有明确标签的保险箱里。当然,数据被保存起来了,但检索数据却成了一个猜谜游戏。

明确我们正在传递的消息通常会减少以后的麻烦。

“那么,什么时候适合使用 context.Value() ?”

最好限制它的使用范围,但 Go 文档建议在跨API和进程间传递请求范围的值时使用它。以下是一些很好的用途:

你可以考虑使用它来跟踪某些与请求相关的数据,例如:

  • 跟踪请求的开始时间
  • 记录访问者的IP地址
  • 管理追踪和跨度IDs
  • 识别正在访问的HTTP路由

上面例子中 ‘payment’ 支付数据与请求无关吗?

如果 ‘payment’ 支付信息在多个函数中都很重要,那么在函数参数显示传递它会更清晰、安全,并且有助于任何阅读代码的人立即理解该函数直接与‘payment’支付数据交互。

一般来说,最好避免在 context 中嵌入关键业务数据,这种策略可以保持代码清晰度和可维护性。

3. 使用context.WithoutCancel 保持 context 活跃

当在Go中实用context时,非常简单的一件就是直接使用带有取消功能的context。如果取消父级context,所有子context也会被取消。

比如,下面这个简单的例子:

parentCtx, cancel := context.WithCancel(context.Background())
childCtx, _ := context.WithCancel(parentCtx)go func(ctx context.Context){<-ctx.Done()fmt.Println("Child context done")
}(childCtx)cancel()

此段代码中,一旦我们取消 parentCtx, childCtx 也会被取消。这通常是我们想要的,但有时我们可能需要一个子context能够继续运行,即使父级context被取消了。

在Go中处理HTTP请求时,我们会经常遇到一个场景:在处理主请求后启动goroutine处理任务,如果处理不仔细可能会导致错误:

func handleRequest(req *http.Request){ctx := req.Context()go hookAfterRequest(ctx)
}

在我们考虑处理HTTP请求时,即使客户端断开连接,我们仍然需要记录详细信息并收集指标,而不是取消运行。

未完待翻译,感兴趣可以先看原仓库英文版。喜欢给个鼓励 star !
中文:Go实用技巧
英文:go-practical-tips

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/875396.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

教学用MQTT工具的思考

前言 我在《智能物联网应用设计》课程中有个实验就是学习MQTT的使用&#xff0c;目前使用的是以下几个工具&#xff1a; 客户端使用MQTTX本地服务器使用的是mosquitto 云端服务器采用的巴法云协议分析软件采用的是Wireshark 这里Wireshark基本没有啥可以替代的&#xff0c;而…

Vue3 study

Vue3 工程 创建 还是能像 vue2 一样通过 vue-cli 创建&#xff0c;即 vue create projectName 但是官方更推荐 vite 创建&#xff0c;即 npm create vuelatest&#xff0c;然后从项目名开始配置 总结&#xff1a;入口在 index.html&#xff0c;它会引入 main.ts&#xff0c;…

Win11 操作(四)g502鼠标连接电脑不亮灯无反应

罗技鼠标连接电脑不亮灯无反应 前言 罗技技术&#x1f4a9;中&#x1f4a9;&#xff0c;贴吧技术神中神&#xff01; 最近买了一个g502&#xff0c;结果买回来直接插上电脑连灯都不亮&#xff0c;问了一下客服。客服简单的让我换接口&#xff0c;又是下载ghub之类的&#xf…

Go 1.22 remote error: tls: handshake failure

Golang 1.22 remote error: tls: handshake failure 1.22之前运行下面代码是没有错误 package mainimport ("crypto/tls""fmt""net/http" )func main() {http.DefaultTransport.(*http.Transport).TLSClientConfig &tls.Config{InsecureS…

从零开始!JupyterNotebook的安装教程

安装 Anaconda 1、下载 Anaconda&#xff1a; 访问 Anaconda 官方网站 (https://www.anaconda.com/products/distribution/) 下载适合您操作系统的 Anaconda 发行版。 2、安装 Anaconda&#xff1a; Windows&#xff1a;运行下载的安装程序&#xff0c;选择“Just Me”…

Leetcode—297. 二叉树的序列化与反序列化【困难】

2024每日刷题&#xff08;148&#xff09; Leetcode—297. 二叉树的序列化与反序列化 实现代码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode(int x) : val(x), left(NULL), right(…

Esxi 上的 CentOS 7.6 系统中搭建本地 Yum 源

1. 挂载 CentOS 安装盘 在 ESXi 管理界面中&#xff0c;将 CentOS 安装 ISO 文件挂载到虚拟机。 2. 挂载光盘镜像 在虚拟机中执行以下命令&#xff0c;将安装盘挂载到 /mnt/cdrom&#xff1a; mkdir /mnt/cdrom mount /dev/cdrom /mnt/cdrom3. 禁用所有默认的 YUM 源 进入…

4. kubernetes资源——deployment无状态负载

kubernetes资源——deployment无状态负载 一、deployment无状态负载1、deployment无状态负载 二、创建deployment1、创建deployment2、验证副本维护 三、deployment滚动更新1、创建pod2、测试滚动更新流程2.1、修改镜像版本、或者副本数2.2、执行更新2.3、查看更新过程2.4、查看…

低代码+工作流:拔高企业效率的数字化神器

前言 传统的软件开发过程中&#xff0c;随着产品业务的不断更新迭代&#xff0c;会产生大量的重复性的工作。这些重复性的工作其实是遵循着某种特定的规则&#xff0c;假如在开发阶段我们没有做好很好的抽象&#xff0c;在后期做新业务新产品时&#xff0c;我们仍然要花费大量…

AutoMySQLBackup execution.. Backup failed Docker部署mysql 自动备份失败!!

摘要&#xff1a; Docker容器部署的mysql5.7版本遇到使用AutoMYSQLBackup备份失败了&#xff0c;反复修改automysqlbackup.conf也不起效。这里推荐一种新的办法绕开老路子直接备份。 目录 一、环境介绍 二、AutoMYSQLBackup 三、问题描述 四、解决思路 4.1第一种解决思…

Java黑色界面陪玩高端小程序源码陪练APP源码H5公众号源码电竞系统

&#x1f680;【电竞新纪元】解锁高端陪玩小程序源码 & 陪练APP秘籍&#xff0c;H5公众号全攻略&#xff01; &#x1f3ae; 开篇&#xff1a;电竞热潮下的新机遇 Hey游戏迷们&#xff01;随着电竞行业的蓬勃发展&#xff0c;你是否也想在这股浪潮中分得一杯羹&#xff1…

学习笔记9:雪花算法

雪花算法 雪花算法&#xff08;Snowflake Algorithm&#xff09;是一种生成唯一ID的算法&#xff0c;最初由Twitter开发。它的主要特点是生成的ID是64位的长整型数字&#xff0c;具有以下特性&#xff1a; 唯一性&#xff1a;每个生成的ID都是唯一的。趋势递增&#xff1a;生…

Python爬虫小项目实战

1.自动获取小说多个章节内容 2.获取英雄联盟里面的全部英雄 3. 简单地自动抽奖系统 4. 简单地点赞系统 5. 制作查询手机号工具 6. 制做登录系统 7. 操作excel办公自动化 8. 自动批量保存图片 9. 获取NBA数据 10. 获取彩票信息 11. 获取房地产信息 12. 获取小说…

opencascade AIS_Manipulator源码学习

前言 AIS_Manipulator 是 OpenCASCADE 库中的一个类&#xff0c;用于在3D空间中对其他交互对象或一组对象进行局部变换。该类提供了直观的操控方式&#xff0c;使用户可以通过鼠标进行平移、缩放和旋转等操作。 详细功能 交互对象类&#xff0c;通过鼠标操控另一个交互对象…

git 操作汇总【迭代更新中】

文章目录 0x1初始化操作0x11 生成公钥0x12 配置账号和邮箱 0x20x21 拉取代码0x22 推送代码0x23 设置远端分支 0x30x31 提交mr 0x40x41 子模块0x42 子模块添加 0x1初始化操作 0x11 生成公钥 ssh-keygen0x12 配置账号和邮箱 git config --global user.name username git confi…

瀚高数据库初级考试认证

pg_dumpall可以转储全局角色和表空间信息 单选题2分 A. 是 B. 否 回答正确(2分) 答案&#xff1a; A 解析&#xff1a;pg_dumpall备份一个给定集簇中的每一个数据库&#xff0c;并且也保留了集簇范围的数据&#xff0c;如角色和表空间定义。 2. 自定义文件格式必须与pg_restore…

【网络安全】构建稳固与安全的网络环境:从“微软蓝屏”事件中汲取的教训

发生什么事了&#xff1f; 近日&#xff0c;一次由微软视窗系统软件更新引发的全球性“微软蓝屏”事件&#xff0c;不仅成为科技领域的热点新闻&#xff0c;更是一次对全球IT基础设施韧性与安全性的深刻检验。这次事件&#xff0c;源于美国电脑安全技术公司“众击”提供的一个…

用uniapp 及socket.io做一个简单聊天app1

####相关的表结构&#xff0c;用的是mysql 用户表&#xff08;Users&#xff09; 存储用户的基本信息。 CREATE TABLE Users (id INT AUTO_INCREMENT PRIMARY KEY,username VARCHAR(50) NOT NULL UNIQUE,password VARCHAR(100) NOT NULL,email VARCHAR(100) UNIQUE,created_a…

Layui Selcet选择框动态选择问题

前言 时隔多日我也是重新回归写作&#xff0c;高考已经完毕&#xff0c;我将继续我的文章创作&#xff0c;今天我将分享的是我在开发我自己的一个新项目所遇到的问题&#xff0c;这里预告一下我的新项目: VitaApi管理系统 这个系统可以看作是萌新源api管理系统的延续&#xff…

前端学习6——自学习梳理

dom操作&#xff1a;让js和Html真正交互起来 dom&#xff08;document object model&#xff09; 内含利用dom操作进行河北大学网页的简单设计() <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name&qu…