• Go 如何使用Singleflight来减少重复进程
  • 发布于 2个月前
  • 571 热度
    0 评论
介绍
有许多方法可以优化代码以提高效率,减少运行进程就是其中之一。在本文中,我们将看到如何通过使用一个Go包Singleflight来减少重复进程,从而优化Go代码。

问题
假设你有一个web应用,它每秒有10个请求(RPS)。根据您所知道的数据,其中一些请求具有相同的模式,实际上可以生成相同的结果,这意味着实际上存在冗余流程。

从上面的插图中,我们知道用户1和用户2想要相同的东西,但最终,我们(大多数情况下)分别处理这两个请求。

解决方案
Singleflight是可以解决这类问题的Go包之一,如文档中所述,它提供了重复函数调用抑制机制。很酷,如果我们知道我们要调用的函数是重复的,我们就可以减少处理的函数的数量,让我们看看在现实世界中如何使用它。

实现
我们将创建两个程序,server.go 和 client.go。
server.go — 将作为web服务,可以接收 /api/v1/get_something 的请求,参数名为name
// server.go

package main

import (
"fmt"
"net/http"
)

func main() {
http.HandleFunc("/api/v1/get_something", func(w http.ResponseWriter, r *http.Request) {
name := r.URL.Query().Get("name")
response := processingRequest(name)
_, _ = fmt.Fprint(w, response)
})

err := http.ListenAndServe(":15001", nil)
if err != nil {
fmt.Println(err)
}
}

func processingRequest(name string) string {
fmt.Println("[DEBUG] processing request..")
return "Hi there! You requested " + name
}
client.go — 将作为一个客户端,向web服务发出5个并发请求(你可以在变量totalRequests中设置这个数字)。
// client.go

package main

import (
    "io"
    "log"
    "net/http"
    "sync"
)

func main() {
    // 堆代码 duidaima.com
    var wg sync.WaitGroup
    endpoint: = "http://localhost:15001/api/v1/get_something?name=something"
    totalRequests: = 5

    for i: = 0;
    i < totalRequests;
    i++{
        wg.Add(1)
        go func(i int) {
            defer wg.Done()
            makeAPICall(endpoint)
        }(i)
    }
    wg.Wait()

}

func makeAPICall(endpoint string) {
    resp, err: = http.Get(endpoint)
    if err != nil {
        log.Fatalln(err)
    }

    body, err: = io.ReadAll(resp.Body)
    if err != nil {
        log.Fatalln(err)
    }
    result: = string(body)
    log.Printf(result)
}
首先,我们可以运行 server.go,然后继续执行 client.go。我们将在服务器脚本的终端中看到如下内容:
[DEBUG] processing request.. 
[DEBUG] processing request.. 
[DEBUG] processing request.. 
[DEBUG] processing request.. 
[DEBUG] processing request..
客户端的输出是这样的:
2023/09/05 10:29:34 Hi there! You requested something
2023/09/05 10:29:34 Hi there! You requested something
2023/09/05 10:29:34 Hi there! You requested something
2023/09/05 10:29:34 Hi there! You requested something
2023/09/05 10:29:34 Hi there! You requested something
这是正确的,因为我们从客户端发送了五个请求,并在服务器中处理了这五个请求。现在让我们在代码中实现Singleflight,这样它会更有效率。
// server.go
package main
import (
    "fmt"
    "net/http"
    "golang.org/x/sync/singleflight"
)

var g = singleflight.Group {}
func main() {
    http.HandleFunc("/api/v1/get_something", func(w http.ResponseWriter, r * http.Request) {
        name: = r.URL.Query().Get("name")
        response,
        _,
        _: = g.Do(name, func()(interface {}, error) {
            result: = processingRequest(name)
            return result,
            nil
        })
            _,
        _ = fmt.Fprint(w, response)
    })

    err: = http.ListenAndServe(":15001", nil)
    if err != nil {
        fmt.Println(err)
    }
}

func processingRequest(name string) string {
    fmt.Println("[DEBUG] processing request..")
    return "Hi there! You requested " + name
}
重新启动服务器并再次运行客户端程序后,服务器的终端显示如下:
[DEBUG] processing request..
[DEBUG] processing request..
客户端的输出还是没有变化:
2023/09/05 10:32:49 Hi there! You requested something
2023/09/05 10:32:49 Hi there! You requested something
2023/09/05 10:32:49 Hi there! You requested something
2023/09/05 10:32:49 Hi there! You requested something
2023/09/05 10:32:49 Hi there! You requested something
太好了!所有客户端都得到了预期的响应,但是现在我们的服务器只处理了两个请求。想象一下,如果您处理数千个类似的请求,您将带来多大的效率,这是惊人的!

结论
在本文中,我们了解了Singleflight在优化代码方面的强大功能。不仅仅是处理一个web请求,你还可以将它的用例扩展到其他事情上,比如从数据库中获取数据等等。
用户评论