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

2023-10-31 17:12:33 浏览数 (1)

Golang 优雅的计算接口耗时

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

代码语言:javascript复制
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 msn", time.Since(t0).Millisecond())

	// 正确做法,将输出函数放在匿名函数中,函数里的相关变量计算将会在程序结束时执行,就可以达到我们想要的结果了。
	defer func() {
		fmt.Printf("Use Time %d msn", 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)
}

执行结果:

代码语言:javascript复制
$ go run .main.go
Use Time 207 ms

Golang 优雅的接口限流思路

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

代码语言:javascript复制
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 函数调用并发 %dn", 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)
}

执行结果:

代码语言:javascript复制
$ 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 多路复用,实现数据库查询接口的超时处理。

示例:

代码语言:javascript复制
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)
}

执行结果:

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

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

0 人点赞