Golang | 优雅的计算接口耗时、接口限流以及接口超时处理思路

欢迎关注「全栈工程师修炼指南」公众号

设为星标⭐每天带你 基础入门 到 进阶实践 再到 放弃学习

专注 企业运维实践、网络安全、系统运维、应用开发、物联网实战、全栈文章 等知识分享

  花开堪折直须折,莫待无花空折枝 


作者主页:[ https://www.weiyigeek.top ]  

博客:[ https://blog.weiyigeek.top ]

作者<安全开发运维>答疑交流群,回复【学习交流群】即可加入


文章目录:

  • Golang 优雅的计算接口耗时

  • Golang 优雅的接口限流思路

  • Golang 优雅的接口超时控制

Golang 优雅的计算接口耗时

描述: Goglang 接口耗时监控测试用例
核心:使用 defer + 匿名函数 再加上 time.Since() 函数实现再程序结束完毕时计算此代码片段(接口)执行耗时
示例:

package main

import (
	"fmt"
	"time"
)

/**
	Goglang 接口耗时监控测试用例
	核心:使用 defer + 匿名函数 再加上 time.Since() 函数实现再程序结束完毕时计算此代码片段(接口)执行耗时
**/

// 模拟接口耗时计算处理
func timeConsumingInterface(a, b int) string {
	t0 := time.Now()
	// 此处需要注意 defer 的特性
	// 错误做法,它会在声明时便会将变量进行执行,所以在输出时使用时间为 0ms, 这显示我们想看到的。
	// defer fmt.Printf("Use Time %d ms\n", time.Since(t0).Millisecond())

	// 正确做法,将输出函数放在匿名函数中,函数里的相关变量计算将会在程序结束时执行,就可以达到我们想要的结果了。
	defer func() {
		fmt.Printf("Use Time %d ms\n", time.Since(t0).Milliseconds())
	}()

	if a > b {
		// 模拟程序耗时
		time.Sleep(100 * time.Millisecond)
		return "ok, a > b"
	} else {
		// 模拟程序耗时
		time.Sleep(200 * time.Millisecond)
		return "ok, a < b"
	}
}

func main() {
	// 模拟一百并发调用
	timeConsumingInterface(5, 6)
	time.Sleep(3 * time.Second)
}

执行结果:

$ go run .\main.go
Use Time 207 ms

Golang 优雅的接口限流思路

描述: Goglang 接口限流测试用例,此处以模拟数据库访问函数 readDB() 为例。
核心:利用make申请一个带容量的管道来实现。
示例:

package main

import (
	"encoding/json"
	"fmt"
	"sync/atomic"
	"time"
)

/**
	Goglang 接口限流测试用例,此处以模拟数据库访问函数 readDB() 为例。
	核心:利用make申请一个带容量的管道来实现。
**/
type Res struct {
	Username string `json:"username"`
	Status   string `josn:"status"`
}

var (
	countnum       int32
	countnum_limit = make(chan struct{}, 10) // 开辟容量为10的管道
)

// 模拟,数据库SQL请求查询
func readDB() string {
	atomic.AddInt32(&countnum, 1)        // 原子操作+1
	defer atomic.AddInt32(&countnum, -1) // 原子操作-1,defer 在退出时执行
	fmt.Printf("ReadDB 函数调用并发 %d\n", atomic.LoadInt32(&countnum))
	time.Sleep(200 * time.Millisecond) // 200 毫秒
	var res = &Res{Username: "WeiyiGeek", Status: "ok"}
	value, err := json.Marshal(res)
	if err != nil {
		fmt.Println(err)
	}
	return string(value) // {"username":"WeiyiGeek","status":"ok"}
}

// 模拟接口限流处理
func flowControlInterface() {
	countnum_limit <- struct{}{}
	readDB()
	// 读取完毕后取出管道数据,防止达到10之后阻塞。
	<-countnum_limit
}

func main() {
	// 模拟一百并发调用
	for i := 0; i < 100; i++ {
		go flowControlInterface()
	}
	time.Sleep(3 * time.Second)
}

执行结果:

$ go run ./main.go
ReadDB 函数调用并发 1
ReadDB 函数调用并发 2
ReadDB 函数调用并发 3
ReadDB 函数调用并发 4
ReadDB 函数调用并发 5
ReadDB 函数调用并发 6
ReadDB 函数调用并发 7
ReadDB 函数调用并发 8
ReadDB 函数调用并发 9
ReadDB 函数调用并发 10
ReadDB 函数调用并发 10
.....
ReadDB 函数调用并发 10
ReadDB 函数调用并发 10
ReadDB 函数调用并发 10
ReadDB 函数调用并发 9
ReadDB 函数调用并发 10
ReadDB 函数调用并发 9

亲,文章就要看完了,不关注一下【全栈工程师修炼指南】吗?

Golang 优雅的接口超时控制

描述: Goglang 接口超时控制测试用例
核心:使用管道chan 加上 select 多路复用,实现数据库查询接口的超时处理。

示例:

package main

import (
	"net/http"
	"time"
)

/**
	Goglang 接口超时控制测试用例
	核心:使用管道chan 加上 select 多路复用,实现数据库查询接口的超时处理。
**/

// 模拟数据库访问函数
func readDB() string {
	time.Sleep(200 * time.Millisecond)
	return "{\"name\":\"weiyigeek\",\"公众号\":\"全栈工程师修炼指南\"}"
}

// 模拟接口超时示例
func timeoutInterface(w http.ResponseWriter, req *http.Request) {
	var resp string
	// 创建一个chan管道
	ch := make(chan struct{}, 1)

	// 创建一个协程来调用数据库访问函数
	go func() {
		resp = readDB()
		// 向管道写入一个空结构体
		ch <- struct{}{}
	}()

	// 使用 select 多路复用来实现一个超时控制
	select {
	// 当数据库调用完毕则执行取出
	case <-ch:
	// 假如此300毫秒先到了,而readDB()还没有执行完毕则返回超时信息。
	// 300ms => 此实践中并不会触发超时,这是由于我们模拟的数据库读取还是比较简单的。
	// 此处使用 100s 来验证超时
	case <-time.After(100 * time.Millisecond):
		resp = "{\"err\":\"数据库读取超时.\"}"
	}

	w.Write([]byte(resp))
}

func main() {
	http.HandleFunc("/", timeoutInterface)
	http.ListenAndServe("127.0.0.1:5678", nil)
}

执行结果:

2e88d8361b9be5c85527e8e6ba4cf3b3.png

本文至此完毕,更多技术文章,尽情等待下篇好文!

原文地址: https://blog.weiyigeek.top

如果此篇文章对你有帮助,请你将它分享给更多的人! 

d1acc8b5c26d7258c08cb610232f4dd8.gif

c04a7b717def00e74fbb6c0f044616ad.png 学习书籍推荐 往期发布文章 9c2dafee9f36fd82296c7b5dbcc5e14b.png

公众号回复【0008】获取【Ubuntu22.04安装与加固脚本】

公众号回复【10001】获取【WinServer安全加固脚本】

公众号回复【10002】获取【KylinOS银河麒麟安全加固脚本】

公众号回复【0011】获取【k8S二进制安装部署教程】

公众号回复【0014】获取【Nginx学习之路汇总】

公众号回复【0015】获取【Jenkins学习之路汇总】

 热文推荐  

欢迎长按(扫描)二维码 取更多渠道哟!

欢迎关注 【全栈工程师修炼指南】(^U^)ノ~YO

添加作者微信【weiyigeeker】,拉你一起学习交流吧!

关注回复【学习交流群】即可加入【安全开发运维沟通交流群

温馨提示: 由于作者水平有限,本章错漏缺点在所难免,希望读者批评指正,若有问题或建议请在文章末尾留下您宝贵的经验知识,或联系邮箱地址 master@weiyigeek.top 或 关注公众号 [全栈工程师修炼指南] 留言。

万水千山总是情,点个【赞 + 在看】吧!

点击【"阅读原文"】获取更多有趣的知识!   

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在Golang中,泛型接口是一种接口类型,可以用于处理不同类型的数据。泛型接口在编程中非常有用,因为它允许我们编写可重用、灵活的代码,而无需针对特定类型进行硬编码。 在Golang中,泛型接口可以通过使用空接口(`interface{}`)来实现。空接口是一个没有任何方法的接口,可以接受任何类型的值。通过使用空接口,可以实现泛型的功能,使得接口可以接收任何类型的数据。 使用泛型接口,我们可以在不改变接口定义的情况下,接受不同类型的参数。例如,我们可以定义一个泛型接口`Container`,用于表示一个可以容纳不同类型元素的容器。这个接口可以定义添加元素、删除元素以及获取元素等方法。 使用泛型接口的好处是可以编写灵活的代码,尽可能减少重复代码的编写。由于泛型接口可以处理多种类型的数据,我们可以将相同的逻辑应用于不同的数据类型,实现代码的重用。 然而,目前Golang没有原生支持泛型接口的功能,因此在实现泛型接口时可能需要一些额外的代码处理。一种常见的做法是使用类型断言来判断接口的实际类型,然后进行相应的操作。 总而言之,虽然Golang没有内置的泛型功能,但通过使用空接口和类型断言,我们可以实现泛型接口从而处理不同类型的数据,提高代码的重用性和灵活性。 ### 回答2: Go语言是一种静态类型的编程语言,其最近的版本Go 1.18中引入了泛型接口的概念。泛型指的是在编写代码时不指定具体类型,而是允许使用者在使用时根据自己的需求来指定具体的类型。 在传统的面向对象编程中,常用的接口表示方式是通过接口类型断言来判断对象是否实现了某个接口。但是这种方式在处理不同类型的数据时需要进行类型转换,不够灵活且有一定的性能损耗。 而泛型接口则可以在接口定义时使用类型参数,通过类型参数来指定接口的具体类型。这样一来,在使用时就可以直接将对应类型的数据传入接口中,无需进行类型转换。 泛型接口的引入为Go语言提供了更加灵活和高效的编程方式。通过泛型接口,我们可以编写更加通用和复用的代码。它还能帮助我们更好地约束函数和数据类型之间的关系,提高代码的健壮性和可读性。 不过需要注意的是,泛型接口的引入也会带来一定的复杂性。在使用泛型接口时,我们需要仔细考虑类型参数的合理性和边界条件,并且需要充分测试以确保代码的正确性。 总之,引入泛型接口是Go语言进一步发展的一大步。它提供了更多的编程方式,并且可以在一定程度上简化代码和提高效率。希望未来随着泛型接口的进一步成熟和普及,我们可以看到更多高质量、灵活和通用的Go代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值