Optimize your Go code using Singleflight

Photo by James Harrison on UnsplashIntroductionThere are many ways to optimize your code to achieve more efficiency, and reducing running processes is one of them. In this article, we are going to see how we can optimize a Go code by reducing duplicate…


This content originally appeared on Level Up Coding - Medium and was authored by Dzaky Widya Putra

Photo by James Harrison on Unsplash

Introduction

There are many ways to optimize your code to achieve more efficiency, and reducing running processes is one of them. In this article, we are going to see how we can optimize a Go code by reducing duplicate processes using one of the Go packages, Singleflight.

Problem

Let’s say you have a web app, it has 10 requests per second (RPS). Based on the data you know some of those requests have the same pattern that can actually generate the same result, which means you actually have redundant processes.

Image 1: An illustration of user 1 and user 2 making the same requests

From the illustration above, we know user 1 and user 2 want the same thing, but in the end, we (mostly) are processing both requests separately.

Solution

Singleflight is one of the Go packages that can solve that kind of problem, as described in the documentation, it provides a duplicate function call suppression mechanism.

Cool, so we can actually decrease the number of functions we process if we know that the functions we are going to call are duplicated, let’s see how we can use it in the real-world case.

Implementation

We are going to create two programs, server.go and client.go .

server.go — will act as the web service that can receive requests at the endpoint /api/v1/get_something with a parameter called 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(":8080", 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 will act as a client that makes 5 concurrent requests to the web service (you can set the number in a variable totalRequests)

// client.go

package main

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

func main() {

var wg sync.WaitGroup

endpoint := "http://localhost:8080/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 := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatalln(err)
}

result := string(body)
log.Printf(result)
}

First, we can run the server.go then continue by client.go. We’ll see in the terminal of the server’s script something like this:

[DEBUG] processing request..
[DEBUG] processing request..
[DEBUG] processing request..
[DEBUG] processing request..
[DEBUG] processing request..

The terminal of the client’s script would be like this:

Hi there! You requested something
Hi there! You requested something
Hi there! You requested something
Hi there! You requested something
Hi there! You requested something

It makes sense, since we sent five requests from the clients, and processed those five requests in the server.

Now let’s implement Singleflight in our code so that it would be more efficient.

// 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(":8080", nil)
if err != nil {
fmt.Println(err)
}
}

func processingRequest(name string) string {
fmt.Println("[DEBUG] processing request..")
return "Hi there! You requested " + name
}

After we restarted the server and run the client’s program again, the terminal in the server’s script shows this:

[DEBUG] processing request..
[DEBUG] processing request..

The terminal of the client’s script shows this:

Hi there! You requested something
Hi there! You requested something
Hi there! You requested something
Hi there! You requested something
Hi there! You requested something

That’s great! All the clients get the expected responses, but now our server only processed two requests. Imagine the size of efficiency you will bring if you are processing thousands of similar requests, it’s amazing!

Conclusion

In this article, we learned the power of Singleflight in optimizing our code. Not only in handling a web request, but you can also expand the use case of it to other things like getting the data from the database, etc.

There are also things that I didn’t cover in this article for example what if the process in Singleflight fails, and how we can mitigate it. That might be a topic I want to explore later in the next articles.

Lastly, thank you very much if you are still reading up to this point, please do share the article if you find it useful or might know someone who needs it.

Level Up Coding

Thanks for being a part of our community! Before you go:

🚀👉 Join the Level Up talent collective and find an amazing job


Optimize your Go code using Singleflight was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.


This content originally appeared on Level Up Coding - Medium and was authored by Dzaky Widya Putra


Print Share Comment Cite Upload Translate Updates
APA

Dzaky Widya Putra | Sciencx (2023-02-08T15:17:48+00:00) Optimize your Go code using Singleflight. Retrieved from https://www.scien.cx/2023/02/08/optimize-your-go-code-using-singleflight/

MLA
" » Optimize your Go code using Singleflight." Dzaky Widya Putra | Sciencx - Wednesday February 8, 2023, https://www.scien.cx/2023/02/08/optimize-your-go-code-using-singleflight/
HARVARD
Dzaky Widya Putra | Sciencx Wednesday February 8, 2023 » Optimize your Go code using Singleflight., viewed ,<https://www.scien.cx/2023/02/08/optimize-your-go-code-using-singleflight/>
VANCOUVER
Dzaky Widya Putra | Sciencx - » Optimize your Go code using Singleflight. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2023/02/08/optimize-your-go-code-using-singleflight/
CHICAGO
" » Optimize your Go code using Singleflight." Dzaky Widya Putra | Sciencx - Accessed . https://www.scien.cx/2023/02/08/optimize-your-go-code-using-singleflight/
IEEE
" » Optimize your Go code using Singleflight." Dzaky Widya Putra | Sciencx [Online]. Available: https://www.scien.cx/2023/02/08/optimize-your-go-code-using-singleflight/. [Accessed: ]
rf:citation
» Optimize your Go code using Singleflight | Dzaky Widya Putra | Sciencx | https://www.scien.cx/2023/02/08/optimize-your-go-code-using-singleflight/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.