Search⌘ K
AI Features

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...

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 flag package provides a ...