Sling Academy
Home/Golang/Handling Concurrent Requests in Go Servers

Handling Concurrent Requests in Go Servers

Last updated: November 27, 2024

Handling concurrent requests efficiently is a vital aspect of developing web servers. Go, with its built-in support for concurrent programming using goroutines, provides powerful tools for managing concurrency.

Understanding Concurrency in Go

Concurrency in Go is managed through goroutines and channels. A goroutine is a function capable of running concurrently with other functions, making it a great fit for web servers handling multiple requests at any given time.

Creating a Basic Go Server

To handle concurrent requests, let's begin with setting up a simple Go server:

package main

import (
    "fmt"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello, World!")
    })

    http.ListenAndServe(":8080", nil)
}

This minimal Go server setup uses the http package to listen for requests on port 8080.

Handling Concurrent Requests

The Go server by default is ready to handle concurrent requests efficiently. Each incoming request is handled in a separate goroutine. This can be verified by augmenting the server with logging for each request:

package main

import (
    "fmt"
    "net/http"
    "time"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        go handleRequest(w, r)
    })

    http.ListenAndServe(":8080", nil)
}

func handleRequest(w http.ResponseWriter, r *http.Request) {
    start := time.Now()
    fmt.Fprintf(w, "Hello, World!")
    fmt.Printf("Handled request in %v\n", time.Since(start))
}

Here, handleRequest is called in a separate goroutine. This enables handling multiple requests concurrently based on scheduled tasks by the Go scheduler.

Managing Goroutines

Usually, the Go runtime does an excellent job in balancing goroutines for HTTP requests, but explicit management of concurrent executions might be necessary for resource handling or complete control over request limits.

Using channels, developers can control how goroutines are synchronized. Here’s an example that uses a channel to limit the number of concurrently processed HTTP requests:

package main

import (
    "fmt"
    "net/http"
    "time"
)

func main() {
    // Limiting to max 5 concurrent requests
    limit := make(chan struct{}, 5)
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        limit <- struct{}{}
        go handleLimitedRequest(w, r, limit)
    })

    http.ListenAndServe(":8080", nil)
}

func handleLimitedRequest(w http.ResponseWriter, r *http.Request, limit chan struct{}) {
    defer func() { <-limit }()

    start := time.Now()
    fmt.Fprintf(w, "Hello, Concurrent World!")
    fmt.Printf("Request processed in %v\n", time.Since(start))
}

This setup makes sure that no more than five requests are being processed concurrently, effectively using channels to throttle the in-flight requests.

Conclusion

In Go servers, handling concurrency properly can immensely improve the performance and reliability of applications. By utilizing goroutines and channels, developers can finely control the flow and limit concurrent request processing, ensuring robust and efficient web server solutions.

Next Article: Load Balancing HTTP Servers in Go

Previous Article: Debugging Network Issues in Go Applications

Series: Networking and Server

Golang

Related Articles

You May Also Like

  • How to remove HTML tags in a string in Go
  • How to remove special characters in a string in Go
  • How to remove consecutive whitespace in a string in Go
  • How to count words and characters in a string in Go
  • Relative imports in Go: Tutorial & Examples
  • How to run Python code with Go
  • How to generate slug from title in Go
  • How to create an XML sitemap in Go
  • How to redirect in Go (301, 302, etc)
  • Using Go with MongoDB: CRUD example
  • Auto deploy Go apps with CI/ CD and GitHub Actions
  • Fixing Go error: method redeclared with different receiver type
  • Fixing Go error: copy argument must have slice type
  • Fixing Go error: attempted to use nil slice
  • Fixing Go error: assignment to constant variable
  • Fixing Go error: cannot compare X (type Y) with Z (type W)
  • Fixing Go error: method has pointer receiver, not called with pointer
  • Fixing Go error: assignment mismatch: X variables but Y values
  • Fixing Go error: array index must be non-negative integer constant