golangdown的简单介绍

本文目录一览:

Go 优雅退出实现方法 amp; context原理

1.通过endless包实现

2.通过shutdown实现

在go 1.8.x后,golang在http里加入了shutdown方法,用来控制优雅退出。什么是优雅退出? 简单说就是不处理新请求,但是会处理正在进行的请求,把旧请求都处理完,也就是都response之后,那么就退出。

shutdown通过context上下文实现 。

社区里不少http graceful动态重启,平滑重启的库,大多是基于http.shutdown做的。平滑启动的原理很简单,fork子进程,继承listen fd, 老进程优雅退出。

3.context原理

context 是 Go 并发编程中常用到一种编程模式。

在并发程序中,由于超时、取消操作或者一些异常情况,往往需要进行抢占操作或者中断后续操作。熟悉 channel 的朋友应该都见过使用 done channel 来处理此类问题。比如以下这个例子:

上述例子中定义了一个 buffer 为0的 channel done , 子协程运行着定时任务。如果主协程需要在某个时刻发送消息通知子协程中断任务退出,那么就可以让子协程监听这个 done channel ,一旦主协程关闭 done channel ,那么子协程就可以推出了,这样就实现了主协程通知子协程的需求。这很好,但是这也是有限的。

如果我们可以在简单的通知上附加传递额外的信息来控制取消:为什么取消,或者有一个它必须要完成的最终期限,更或者有多个取消选项,我们需要根据额外的信息来判断选择执行哪个取消选项。

考虑下面这种情况:假如主协程中有多个任务1, 2, …m,主协程对这些任务有超时控制;而其中任务1又有多个子任务1, 2, …n,任务1对这些子任务也有自己的超时控制,那么这些子任务既要感知主协程的取消信号,也需要感知任务1的取消信号。

如果还是使用 done channel 的用法,我们需要定义两个 done channel ,子任务们需要同时监听这两个 done channel 。嗯,这样其实好像也还行哈。但是如果层级更深,如果这些子任务还有子任务,那么使用 done channel 的方式将会变得非常繁琐且混乱。

我们需要一种优雅的方案来实现这样一种机制:

这个时候 context 就派上用场了。

我们首先看看 context 的结构设计和实现原理。

先看 Context 接口结构,看起来非常简单。

Context 接口包含四个方法:

可以看到 Done 方法返回的 channel 正是用来传递结束信号以抢占并中断当前任务; Deadline 方法指示一段时间后当前 goroutine 是否会被取消;以及一个 Err 方法,来解释 goroutine 被取消的原因;而 Value 则用于获取特定于当前任务树的额外信息。而 context 所包含的额外信息键值对是如何存储的呢?其实可以想象一颗树,树的每个节点可能携带一组键值对,如果当前节点上无法找到 key 所对应的值,就会向上去父节点里找,直到根节点,具体后面会说到。

emptyCtx 是一个 int 类型的变量,但实现了 context 的接口。 emptyCtx 没有超时时间,不能取消,也不能存储任何额外信息,所以 emptyCtx 用来作为 context 树的根节点。

但我们一般不会直接使用 emptyCtx ,而是使用由 emptyCtx 实例化的两个变量,分别可以通过调用 Background 和 TODO 方法得到,但这两个 context 在实现上是一样的。那么 Background 和 TODO 方法得到的 context 有什么区别呢?可以看一下官方的解释:

Background 和 TODO 只是用于不同场景下:

Background 通常被用于主函数、初始化以及测试中,作为一个顶层的 context ,也就是说一般我们创建的 context 都是基于 Background ;

而 TODO 是在不确定使用什么 context 的时候才会使用。

下面将介绍两种不同功能的基础 context 类型: valueCtx 和 cancelCtx 。

valueCtx 利用一个 Context 类型的变量来表示父节点 context ,所以当前 context 继承了父 context 的所有信息; valueCtx 类型还携带一组键值对,也就是说这种 context 可以携带额外的信息。 valueCtx 实现了 Value 方法,用以在 context 链路上获取 key 对应的值,如果当前 context 上不存在需要的 key ,会沿着 context 链向上寻找 key 对应的值,直到根节点。

WithValue 用以向 context 添加键值对:

这里添加键值对不是在原 context 结构体上直接添加,而是以此 context 作为父节点,重新创建一个新的 valueCtx 子节点,将键值对添加在子节点上,由此形成一条 context 链。获取 value 的过程就是在这条 context 链上由尾部上前搜寻:

跟 valueCtx 类似, cancelCtx 中也有一个 context 变量作为父节点;变量 done 表示一个 channel ,用来表示传递关闭信号; children 表示一个 map ,存储了当前 context 节点下的子节点; err 用于存储错误信息表示任务结束的原因。

再来看一下 cancelCtx 实现的方法:

可以发现 cancelCtx 类型变量其实也是 canceler 类型,因为 cancelCtx 实现了 canceler 接口。 Done 方法和 Err 方法没必要说了, cancelCtx 类型的 context 在调用 cancel 方法时会设置取消原因,将 done channel 设置为一个关闭 channel 或者关闭 channel ,然后将子节点 context 依次取消,如果有需要还会将当前节点从父节点上移除。

WithCancel 函数用来创建一个可取消的 context ,即 cancelCtx 类型的 context 。 WithCancel 返回一个 context 和一个 CancelFunc ,调用 CancelFunc 即可触发 cancel 操作。直接看源码:

之前说到 cancelCtx 取消时,会将后代节点中所有的 cancelCtx 都取消, propagateCancel 即用来建立当前节点与祖先节点这个取消关联逻辑。

这里或许有个疑问,为什么是祖先节点而不是父节点?这是因为当前 context 链可能是这样的:

当前 cancelCtx 的父节点 context 并不是一个可取消的 context ,也就没法记录 children 。

timerCtx 是一种基于 cancelCtx 的 context 类型,从字面上就能看出,这是一种可以定时取消的 context 。

timerCtx 内部使用 cancelCtx 实现取消,另外使用定时器 timer 和过期时间 deadline 实现定时取消的功能。 timerCtx 在调用 cancel 方法,会先将内部的 cancelCtx 取消,如果需要则将自己从 cancelCtx 祖先节点上移除,最后取消计时器。

WithDeadline 返回一个基于 parent 的可取消的 context ,并且其过期时间 deadline 不晚于所设置时间 d 。

与 WithDeadline 类似, WithTimeout 也是创建一个定时取消的 context ,只不过 WithDeadline 是接收一个过期时间点,而 WithTimeout 接收一个相对当前时间的过期时长 timeout :

首先使用 context 实现文章开头 done channel 的例子来示范一下如何更优雅实现协程间取消信号的同步:

这个例子中,只要让子线程监听主线程传入的 ctx ,一旦 ctx.Done() 返回空 channel ,子线程即可取消执行任务。但这个例子还无法展现 context 的传递取消信息的强大优势。

阅读过 net/http 包源码的朋友可能注意到在实现 http server 时就用到了 context , 下面简单分析一下。

1、首先 Server 在开启服务时会创建一个 valueCtx ,存储了 server 的相关信息,之后每建立一条连接就会开启一个协程,并携带此 valueCtx 。

2、建立连接之后会基于传入的 context 创建一个 valueCtx 用于存储本地地址信息,之后在此基础上又创建了一个 cancelCtx ,然后开始从当前连接中读取网络请求,每当读取到一个请求则会将该 cancelCtx 传入,用以传递取消信号。一旦连接断开,即可发送取消信号,取消所有进行中的网络请求。

3、读取到请求之后,会再次基于传入的 context 创建新的 cancelCtx ,并设置到当前请求对象 req 上,同时生成的 response 对象中 cancelCtx 保存了当前 context 取消方法。

这样处理的目的主要有以下几点:

在整个 server 处理流程中,使用了一条 context 链贯穿 Server 、 Connection 、 Request ,不仅将上游的信息共享给下游任务,同时实现了上游可发送取消信号取消所有下游任务,而下游任务自行取消不会影响上游任务。

context 主要用于父子任务之间的同步取消信号,本质上是一种协程调度的方式 。另外在使用 context 时有两点值得注意:上游任务仅仅使用 context 通知下游任务不再需要,但不会直接干涉和中断下游任务的执行,由下游任务自行决定后续的处理操作,也就是说 context 的取消操作是无侵入的; context 是线程安全的,因为 context 本身是不可变的( immutable ),因此可以放心地在多个协程中传递使用。

golang反射框架Fx

Fx是一个golang版本的依赖注入框架,它使得golang通过可重用、可组合的模块化来构建golang应用程序变得非常容易,可直接在项目中添加以下内容即可体验Fx效果。

Fx是通过使用依赖注入的方式替换了全局通过手动方式来连接不同函数调用的复杂度,也不同于其他的依赖注入方式,Fx能够像普通golang函数去使用,而不需要通过使用struct标签或内嵌特定类型。这样使得Fx能够在很多go的包中很好的使用。

接下来会提供一些Fx的简单demo,并说明其中的一些定义。

1、一般步骤

大致的使用步骤就如下。下面会给出一些完整的demo

2、简单demo

将io.reader与具体实现类关联起来

输出:

3、使用struct参数

前面的使用方式一旦需要进行注入的类型过多,可以通过struct参数方式来解决

输出

如果通过Provide提供构造函数是生成相同类型会有什么问题?换句话也就是相同类型拥有多个值呢?

下面两种方式就是来解决这样的问题。

4、使用struct参数+Name标签

在Fx未使用Name或Group标签时不允许存在多个相同类型的构造函数,一旦存在会触发panic。

输出

上面通过Name标签即可完成在Fx容器注入相同类型

5、使用struct参数+Group标签

使用group标签同样也能完成上面的功能

输出

基本上Fx简单应用在上面的例子也做了简单讲解

1、Annotated(位于annotated.go文件) 主要用于采用annotated的方式,提供Provide注入类型

源码中Name和Group两个字段与前面提到的Name标签和Group标签是一样的,只能选其一使用

2、App(位于app.go文件) 提供注入对象具体的容器、LiftCycle、容器的启动及停止、类型变量及实现类注入和两者映射等操作

至于Provide和Populate的源码相对比较简单易懂在这里不在描述

具体源码

3、Extract(位于extract.go文件)

主要用于在application启动初始化过程通过依赖注入的方式将容器中的变量值来填充给定的struct,其中target必须是指向struct的指针,并且只能填充可导出的字段(golang只能通过反射修改可导出并且可寻址的字段),Extract将被Populate代替。 具体源码

4、其他

诸如Populate是用来替换Extract的,而LiftCycle和inout.go涉及内容比较多后续会单独提供专属文件说明。

在Fx中提供的构造函数都是惰性调用,可以通过invocations在application启动来完成一些必要的初始化工作:fx.Invoke(function); 通过也可以按需自定义实现LiftCycle的Hook对应的OnStart和OnStop用来完成手动启动容器和关闭,来满足一些自己实际的业务需求。

Fx框架源码解析

主要包括app.go、lifecycle.go、annotated.go、populate.go、inout.go、shutdown.go、extract.go(可以忽略,了解populate.go)以及辅助的internal中的fxlog、fxreflect、lifecycle

Golang中国的markdown转HTML怎么实现

使用Markdown写好的文章要如何转换成HTML格式,以方便能发布在不支援Markdown的网站呢?我找到了两个方法:Pandoc与WriteMonkey。

Pandoc是一个转换文件格人与标签语言的通用型工具,只要用下列指令就能把Markdown档案转换成HTML:

“c:\Program Files\pandoc\bin\\pandoc.exe” -f markdown -t html 输入.txt 输出.html

如何用golang搜索抓取淘宝商品

您好

golang搜索抓取淘宝商品需要进行数据的引入,一般是if engine.ToString(val) != “hello” { t.FailNow() } } 传递进去的参数的生命周期是php控制的,在request shutdown的时候内存会被释放。 PHP 回调 Golang type greeting!

原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/251053.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小蓝的头像小蓝
上一篇 2024-12-13 13:32
下一篇 2024-12-13 13:32

相关推荐

  • Python简单数学计算

    本文将从多个方面介绍Python的简单数学计算,包括基础运算符、函数、库以及实际应用场景。 一、基础运算符 Python提供了基础的算术运算符,包括加(+)、减(-)、乘(*)、除…

    编程 2025-04-29
  • Python满天星代码:让编程变得更加简单

    本文将从多个方面详细阐述Python满天星代码,为大家介绍它的优点以及如何在编程中使用。无论是刚刚接触编程还是资深程序员,都能从中获得一定的收获。 一、简介 Python满天星代码…

    编程 2025-04-29
  • Python海龟代码简单画图

    本文将介绍如何使用Python的海龟库进行简单画图,并提供相关示例代码。 一、基础用法 使用Python的海龟库,我们可以控制一个小海龟在窗口中移动,并利用它的“画笔”在窗口中绘制…

    编程 2025-04-29
  • Python樱花树代码简单

    本文将对Python樱花树代码进行详细的阐述和讲解,帮助读者更好地理解该代码的实现方法。 一、简介 樱花树是一种图形效果,它的实现方法比较简单。Python中可以通过turtle这…

    编程 2025-04-28
  • Python大神作品:让编程变得更加简单

    Python作为一种高级的解释性编程语言,一直被广泛地运用于各个领域,从Web开发、游戏开发到人工智能,Python都扮演着重要的角色。Python的代码简洁明了,易于阅读和维护,…

    编程 2025-04-28
  • 用Python实现简单爬虫程序

    在当今时代,互联网上的信息量是爆炸式增长的,其中很多信息可以被利用。对于数据分析、数据挖掘或者其他一些需要大量数据的任务,我们可以使用爬虫技术从各个网站获取需要的信息。而Pytho…

    编程 2025-04-28
  • 如何制作一个简单的换装游戏

    本文将从以下几个方面,为大家介绍如何制作一个简单的换装游戏: 1. 游戏需求和界面设计 2. 使用HTML、CSS和JavaScript开发游戏 3. 实现游戏的基本功能:拖拽交互…

    编程 2025-04-27
  • Guava Limiter——限流器的简单易用

    本文将从多个维度对Guava Limiter进行详细阐述,介绍其定义、使用方法、工作原理和案例应用等方面,并给出完整的代码示例,希望能够帮助读者更好地了解和使用该库。 一、定义 G…

    编程 2025-04-27
  • 2的32次方-1:一个看似简单却又复杂的数字

    对于计算机领域的人来说,2的32次方-1(也就是十进制下的4294967295)这个数字并不陌生。它经常被用来表示IPv4地址或者无符号32位整数的最大值。但实际上,这个数字却包含…

    编程 2025-04-27
  • 制作一个简单的管理系统的成本及实现

    想要制作一个简单的管理系统,需要进行技术选型、开发、测试等过程,那么这个过程会花费多少钱呢?我们将从多个方面来阐述制作一个简单的管理系统的成本及实现。 一、技术选型 当我们开始思考…

    编程 2025-04-27

发表回复

登录后才能评论