From 17b11d21b43f2d9613e83116d125caa592aeeffe Mon Sep 17 00:00:00 2001 From: smallnest Date: Sat, 27 Apr 2024 12:14:51 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BF=BB=E8=AF=91=E6=88=90=E9=80=9A=E9=A1=BA?= =?UTF-8?q?=E7=9A=84=E4=B8=AD=E6=96=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- src/032.md | 43 ++++++++++++++++++++++--------------------- src/043.md | 27 +++++++++++++-------------- src/SUMMARY.md | 1 + 4 files changed, 38 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 2337483..4e0b79e 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ Go tips from [Phuong Le](https://twitter.com/func25). | 29 | Avoid context.Background(), make your goroutines promisable. | stonemax | | 30 | 使用context.WithoutCancel()继续上下文操作 | smallnest | | 31 | Loop labels for cleaner breaks and continues | zhubiaook | -| 32 | Scheduling functions after context cancellation with context.AfterFunc | LinPr | +| 32 | Scheduling functions after context cancellation with context.AfterFunc | LinPr,smallnest | | 33 | Just... Don’t Panic() | baxiang | | 34 | Lead with context, end with options, and always close with an error | lylex | | 35 | Prefer strconv over fmt for converting to/from string | jjjjjim | @@ -95,7 +95,7 @@ Go tips from [Phuong Le](https://twitter.com/func25). | 40 | Handle errors while using defer to prevent silent failures | smallnest | | 41 | Sort your fields in your struct from largest to smallest | justlorain | | 42 | Single Touch Error Handling, Less Noise. | zhubiaook | -| 43 | Gracefully Shut Down Your Application | LinPr | +| 43 | Gracefully Shut Down Your Application | LinPr,smallnest | | 44 | Intentionally Stop with Must Functions | syjs10 | | 45 | Always Manage Your Goroutine Lifetime. | stonemax | | 46 | Avoid using break in switch cases, except when paired with labels | baxiang | diff --git a/src/032.md b/src/032.md index 6163b5b..e6b8771 100644 --- a/src/032.md +++ b/src/032.md @@ -1,41 +1,42 @@ +# Tip #31 使用跳转标签让break和continue语句更简洁 + > 原始链接: [Golang Tip #32: Scheduling functions after context cancellation with context.AfterFunc](https://twitter.com/func25/status/1762087461839364445) +> +在 [tip #30](https://colobu.com/gotips/030.html),我们学习了如何使一个Context在其Context停止时仍能继续运行: +现在,让我们来看一下Go 1.21引入的一项新特性。 -在 tip #30,我们已经知道如何在父 context 停止的时候让 context 继续下去 :https://twitter.com/func25/status/1761388781201174853 +`context.AfterFunc`允许您设置一个回调函数`f`,在ctx结束后(无论因取消还是超时)在新的goroutine中运行。 -现在让我看看在 Go1.21 引入的新特性 -`context.AfterFunc` 可以让你设置一个回调函数 `f`,回调函数会在 `ctx` 结束后在它的上下文运行(无论是因为 `ctx` 被取消或者是超时) ![](./images/032/1.png) -该功能非常适合清理、记录日志或其类型的回收资源任务。 - -*回调函数什么时候执行?* +该特性对于清理、日志记录或其他取消后的任务非常有用。 -回调函数在一个新的 goroutine 中运行,该 goroutine 会在收到父 context 的 `ctx.done` 通道发出的信号后被触发 +> “回调函数何时运行?” -*如果 context 已经被取消了会发生什么?* +回调函数在一个新的goroutine中运行,该goroutine在接收到父级上下文的ctx.done通道发送的信号后被触发。 -回调函数会立刻执行,当然这发生在 go 协程里 +> “如果上下文已经取消了怎么办?” -这里有几个关键点: +回调函数会立即运行,当然也是在一个新的`goroutine`中。 -- 独立运行:,你可以在同一上下文中多次使用 AfterFunc 而不会出现任何问题,设置的每个任务都会独立运行。 -- context结束时立刻执行:当你调用 AfterFunc 时,context被取消,它会在一个新的 go 协程中运行。 -- 你可以取消计划中的函数,提供了一种结束机制(stop)可以结束运行中的回调函数 -- 非阻塞:使用stop机制并不会等待回调函数结束,如果你希望主程序同步等待回调函数结束,你需要自己实现这个逻辑 +以下是几个要点: -我们来简单说下结束机制 `stop()`,它是 `AfterFunc` 的返回值 +- 自行运行:您可以多次使用同一上下文调用`AfterFunc`而没有任何问题,您设置的每个任务都会各自独立运行。 +- 如果上下文已完成则立即运行:如果在调用`AfterFunc`时`ctx`已结束,则它会立即在一个新的goroutine中启动`f`。 +- 可以取消计划中的函数:它为您提供了一个`stop`函数,可以阻止f运行。 +- 非阻塞:使用`stop`不会等待f完成,而是快速停止。如果您需要f和主线程工作保持同步,需要您自行安排。 +接下来我们谈谈AfterFunc返回的stop()函数: ![](./images/032/2.png) -如果我们在上context 结束之前调用 stop(),而此时回调尚未运行(因此实际上,goroutine 尚未被触发),则 stopped 的值将为 true - -这意味着我们成功阻止了回调函数的运行。 +如果我们尚未完成上下文且回调尚未运行(实际上,goroutine尚未被触发)时就调用stop(),那么stopped将为true。 - 如果 stopped 的值为false,这可能意味着其中之一: +这意味着我们成功阻止了回调的运行。 -- 回调函数启动了一个协程正在运行中 -- 回调函数已经被停止了 \ No newline at end of file +如果stop()返回false,则可能意味着: +- 函数f已在新的goroutine中开始运行。 +- 函数`f`已被停止。 \ No newline at end of file diff --git a/src/043.md b/src/043.md index 6f7f51e..3507cb9 100644 --- a/src/043.md +++ b/src/043.md @@ -2,27 +2,26 @@ > 原始连接:[Golang Tip #43: Gracefully Shut Down Your Application ](https://twitter.com/func25/status/1766104130303705226) -当我们讨论优雅地关闭一个应用程序的时候,这里会有几件关键目标我们需要保证: +当我们讨论优雅地关闭应用程序时,有几个关键保证是我们力求实现的: -- 没有新的请求:服务端停止接收新的请求 -- 运行中任务的完成:等待当前运行中的任务到逻辑上的停止点 -- 资源的清理:释放比如数据库连接,打开的文件,网络连接等资源 +- 不接收新请求:服务器停止接受新的请求。 +- 完成正在进行的任务:等待当前处理的任务达到逻辑上的停止点。 +- 资源清理:释放诸如数据库连接、打开文件、网络连接等资源。 -有一些不同的实现方法,但为了简单起见,我尽量给出最简洁的方法: +虽然存在一些不同的实现方式,但为了简化起见,我尝试给出最简短的方法: ![](./images/043/1.png) +首先,我们创建一个(主)上下文,当接收到中断信号(`Ctrl+C`)或`SIGTERM`时将其取消。 -首先,我们创建一个(main)上下文,当收到中断信号`(Ctrl+C)`或 `SIGTERM` 时,该上下文将被取消(canceled)。 +接着我们创建两个goroutine,均由`errgroup`协调(如果您还不了解它,请考虑阅读 https://blog.devtrovert.com/p/go-errgroup-you-havent-used-goroutines): -然后我们创建了两个 go 协程,他们都由 `errgroup` 来管理(如果你不知道 `errgroup` 是什么,可以参考 [Go Errgroup: How to Use Goroutines Effectively (devtrovert.com)](https://blog.devtrovert.com/p/go-errgroup-you-havent-used-goroutines)) +第一个直接启动服务器,但要记住,`ListenAndServe` 始终返回非空错误。 +第二个更有趣,这是我们放置优雅清理代码的地方。这个goroutine等待`gCtx.Done()`关闭,该关闭状态由我们的主ctx传播而来。 -+ 第一个 go 协程很直观,启动一个 server,但是要记住 `ListenAndServe` 函数总是返回非空`(non-nil)`的 error -+ 第二个 go 协程很有意思,在这个协程中我们可以做优雅清理。这个协程等待`gCtx.Done() `关闭,这个关闭事件是从主上下文`(main ctx)`中传递过来的。 +如果您的服务运行在Kubernetes上,应考虑在接收到SIGTERM后不立即终止新请求。 -如果我们的服务运行在 Kubernetes 上,考虑不要在收到新的 `SIGTERM` 信号之后立即终止新请求。 +您的应用程序不应立即终止,而应完成所有活跃请求,并继续监听Pod关闭开始后到达的传入连接。 -您的应用程序不能立即终止,而是要继续完成所有活跃的请求,并且继续监听 Pod 关闭开始后到达的连接。 +Kubernetes可能需要一段时间来更新所有kube-proxy和负载均衡器。 -Kubernetes 更新所有 kube-proxies 和负载均衡器可能需要一些时间。 - -这是简化版本,您可以考虑在服务器配置中添加超时时间,检查错误是否已关闭,在关闭 server 上添加超时 ...... \ No newline at end of file +这是简化版,您可能需要考虑为服务器配置添加超时、检查错误是否关闭、为关闭过程添加超时等。 \ No newline at end of file diff --git a/src/SUMMARY.md b/src/SUMMARY.md index b2d735e..c400ed3 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -30,6 +30,7 @@ - [Tip #29 避免使用 context.Background,使你的协程具备承诺性](./029.md) - [Tip #30 使用context.WithoutCancel()继续上下文操作](./030.md) - [Tip #31 使用跳转标签让break和continue语句更简洁](./031.md) +- [Tip #32 使用跳转标签让break和continue语句更简洁](./032.md) - [Tip #33 尽量...不要使用panic()](./033.md) - [Tip #34 以context开头,以options结尾,并且总是用error来关闭](./034.md) - [Tip #35 转换字符串时优先使用 strconv 而非 fmt](./035.md)