在 Golang 中使用心跳模式
来源:dev.to
时间:2024-12-15 13:16:04 494浏览 收藏
最近发现不少小伙伴都对Golang很感兴趣,所以今天继续给大家介绍Golang相关的知识,本文《在 Golang 中使用心跳模式》主要内容涉及到等等知识点,希望能帮到你!当然如果阅读本文时存在不同想法,可以在评论中表达,但是请勿使用过激的措辞~
在 go 中实现心跳以进行应用程序监控
在平衡数据和软件工程师的过程中,我总是在 golang 中寻找一些不同的东西来学习,了解它是如何工作的,并将其应用到比我在互联网上找到的一些基本传统课程和文章更复杂的事情上。在这篇短文中,我将报告并演示我如何通过 go routines 实现,使用 ticker 来模拟应用程序的心跳(“我还活着”)的时间包,以及通道的使用等。
对于许多人来说,确保调用某个函数的人知道该函数是否正在花费时间、正在处理或处于锁定状态是极其重要的,这对许多人来说并不是新闻。也就是说,出现了其他几个术语,例如跟踪、指标、连接性等,这些术语已在监控应用程序中引入,这些应用程序在大多数情况下使用安装在应用程序服务器上的代理来收集指标并将其发送到可视化所有(或几乎)您的申请状态。这些工具中我们有datadog、newrelic、slack、grafana、jaeger等
我们在这里会得到什么?
当我研究和思考创建一些快速简单的东西来解决一些更高级的 go 概念时,我创建了一个相对简单的应用程序,它利用了心跳模式。无论谁给我打电话,都会收到结果,同时还会收到我是否仍然活跃的信息。在更高级的场景中,根据某些业务特殊性自定义实际上是活动的应用程序可能会很有趣,因为 prometheus 的简单实现可以解决这种情况(应用程序是活动的吗?cpu、内存、打开的 goroutine),但是没有同步和可定制的反馈。
编程一小时!
在结构方面,我只使用 go mod 在包中创建了三个文件:
- dictionary.go:包含要搜索的函数的名称字典。
- task.go:任务包含从字典中扫描名字的功能,同时通过频道+时间节拍通知其是否处于活动状态。
- task_test.go:对task.go中存在的函数执行单元测试,以查看字典数据的响应以及有关应用程序是否仍在运行的反馈!
字典.go
这部分go代码定义了一个名为“dictionary”的变量,它是一个将符文类型字符与字符串关联起来的映射。
每个地图条目都是一个键(符文)和一个值(字符串)。在下面的示例中,键是字母表中的小写字母,值是与每个字母关联的名称。例如,字母“a”与名称“airton”相关联,字母“b”与名称“bruno”相关联,依此类推:
package heartbeat var dicionario = map[rune]string{ 'a': "airton", 'b': "bruno", 'c': "carlos", 'd': "daniel", 'e': "eduardo", 'f': "felipe", 'g': "gustavo", }
任务.go
我在完整代码之后更好地解释了代码的每个部分:
package heartbeat import ( "context" "fmt" "time" ) func processingtask( ctx context.context, letras chan rune, interval time.duration, ) (<-chan struct{}, <-chan string) { heartbeats := make(chan struct{}, 1) names := make(chan string) go func() { defer close(heartbeats) defer close(names) beat := time.newticker(interval) defer beat.stop() for letra := range letras { select { case <-ctx.done(): return case <-beat.c: select { case heartbeats <- struct{}{}: default: } case names <- dicionario[letra]: lether := dicionario[letra] fmt.printf("letra: %s \n", lether) time.sleep(3 * time.second) // simula um tempo de espera para vermos o hearbeats } } }() return heartbeats, names }
导入依赖项
package heartbeat import ( "context" "fmt" "time" )
这里有我的心跳包,它将负责实现在处理任务时以特定时间间隔发送“心跳”的功能。为此,我需要上下文(上下文管理)、fmt(用于字符串格式化)和时间来进行时间控制。
初始函数定义
func processingtask ( ctx context.context, letras chan rune, interval time.duration, ) (<-chan struct{}, <-chan string) {
这是processingtask函数的定义,它接受ctx上下文、字母通道(接收unicode字符的通道)和时间间隔作为参数。该函数返回两个通道:一个心跳通道,为每个“心跳”发送一个空结构;一个名称通道,发送与收到的每个字符对应的字母名称。
渠道
heartbeats := make(chan struct{}, 1) names := make(chan string)
这两行创建了两个通道:heartbeats 是一个缓冲通道,容量为一个元素,names 是一个无缓冲通道。
go routine 完成繁重的工作
go func() defer close(heartbeats) defer close(names) beat := time.newticker(interval) defer beat.stop() for letra := range letras { select { case <-ctx.done(): return case <-beat.c: select { case heartbeats <- struct{}{}: default: } case names <- dicionario[letra]: lether := dicionario[letra] fmt.printf("letra: %s \n", lether) time.sleep(3 * time.second) // simula um tempo de espera para vermos o hearbeats } } }() return heartbeats, names
这是一个匿名goroutine(或在新线程中运行的匿名函数),执行processingtask函数的主要逻辑。它使用 for-range 循环从字母通道读取字符。在循环内,使用 select 从可用选项中选择要执行的操作:
- case <-ctx.done():如果上下文被取消,函数会立即退出,使用 return. 语句
- case <-beat.c:如果节拍指示器发送一个值,则 goroutine 会尝试使用具有空默认值的 select 向心跳通道发送一个空结构。
- case names <-dictionary[letter]:如果收到字母,则 goroutine 从字典字典中获取对应字母的名称,将其发送到名称通道,使用 fmt 包将字母打印到屏幕上,并等待三个继续下一个字符之前的秒数。这种模拟等待是为了让我们能够看到正在发送的“心跳”。
最后,该函数返回心跳并命名通道。
测试应用程序
task_test.go
package heartbeat import ( "context" "fmt" "testing" "time" ) func TestProcessingTask(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) defer cancel() letras := make(chan rune) go func() { defer close(letras) for i := 'a'; i <= 'g'; i++ { letras <- i } }() heartbeats, words := ProcessingTask(ctx, letras, time.Second) for { select { case <-ctx.Done(): return case <-heartbeats: fmt.Printf("Application Up! \n") case letra, err := <-words: if !err { return } if _, notfound := dicionario[rune(letra[0])]; !notfound { t.Errorf("Letra %s não encontrada", letra) } } } }
这里我为前面解释过的processingtask 函数创建了一个go 单元测试。 testprocessingtask 测试函数创建一个超时为 20 秒的上下文和一个 unicode 字符(字母)通道。然后,匿名 goroutine 将歌词发送到歌词通道。然后使用上下文、unicode 字符通道和时间间隔调用processingtask 函数。它返回两个通道,一个心跳通道和一个单词通道。
然后测试函数使用 select 运行无限循环,该循环从三个通道读取:上下文、心跳通道和单词通道。
如果上下文被取消,测试循环就会终止。如果收到心跳,则会显示“application up!”打印到标准输出。如果接收到单词,则测试检查该单词是否存在于字母词典中。如果不存在,则测试失败并显示错误消息。
因此,这个单元测试测试我们的processingtask函数,该函数从一个通道接收字符,将字母名称发送到另一个通道,并在我使用时间限制的上下文中运行时发出“心跳”。啊……它还会检查发送到单词通道的字母名称是否存在于字典中。
我的结论
这段 go 代码阐释了 go 语言和单元测试的一些重要概念:
- 上下文
- 协程
- 频道
- 单元测试(使用 select 监控多个通道)
我的 github 上的完整项目:https://github.com/airtonlira/heartbeatsgolang
领英 - airton lira junior
理论要掌握,实操不能落!以上关于《在 Golang 中使用心跳模式》的详细介绍,大家都掌握了吧!如果想要继续提升自己的能力,那么就来关注golang学习网公众号吧!
-
505 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
280 收藏
-
181 收藏
-
371 收藏
-
236 收藏
-
416 收藏
-
407 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 507次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习