Solution 4: Building Web Services
Explore how to build web services in Go by implementing concurrency using goroutines and channels. Learn to handle HTTP requests, control concurrency levels, and measure request performance effectively in a real-world context.
We'll cover the following...
We'll cover the following...
Solution
Here’s a simple implementation of ab(1) using goroutines and channels in Go.
To run the server side of the ab(1) utility, open a new terminal window and copy and paste the following command into the terminal:
python3 -m http.server 8082
To run the client side, copy and paste the following command into the other terminal window:
go run ab.go -url http://localhost:8082 -c 5 -n 10
Execute the server and client sides in the following playground:
package main
import (
"flag"
"fmt"
"net/http"
"sync"
"io"
"time"
)
func main() {
// Parse command line flags
var (
concurrency int
requests int
url string
)
flag.IntVar(&concurrency, "c", 1, "Number of multiple requests to make at a time")
flag.IntVar(&requests, "n", 1, "Number of requests to perform")
flag.StringVar(&url, "url", "", "URL to test")
flag.Parse()
if url == "" {
fmt.Println("Error: URL is required")
return
}
// Create a channel to track completed requests
done := make(chan bool)
// Create a wait group to synchronize goroutines
var wg sync.WaitGroup
// Start timing the requests
start := time.Now()
// Launch the requested number of goroutines
for i := 0; i < requests; i++ {
wg.Add(1)
go func() {
defer wg.Done()
// Make the HTTP request
resp, err := http.Get(url)
if err != nil {
fmt.Println("Error making request:", err)
return
}
defer resp.Body.Close()
// Read the response body to completion to simulate a real-world scenario
_, _ = io.ReadAll(resp.Body)
// Notify that the request is done
done <- true
}()
// Limit the concurrency
if i%concurrency == 0 {
time.Sleep(time.Millisecond * 10)
}
}
// Calculate and print the results
duration := time.Since(start)
reqsPerSec := float64(requests) / duration.Seconds()
fmt.Println("Concurrency Level: %d\n", concurrency)
fmt.Printf("Time taken for tests: %v seconds\n", duration.Seconds())
fmt.Printf("Complete requests: %d\n", requests)
fmt.Printf("Requests per second: %.2f [#/sec]\n", reqsPerSec)
}
ab.go
Code explanation
Lines 3–9: These are the package imports. The
flagpackage provides a ...