I’m running a simple TCP throughput benchmark using Go 1.24.6.
Both the client and server have abundant CPU, memory, and network resources, and no system-level limits (ulimits, NIC queues, CPU throttling, etc.) are in effect.
However, I’m observing an unexpected behavior:
The throughput of each individual goroutine becomes higher when the overall client concurrency increases.
Example: per-goroutine throughput at concurrency=5 < concurrency=10 < concurrency=15.
This is counterintuitive — I expect each goroutine's performance to remain roughly the same regardless of how many other goroutines are running.
Test Setup ServerThe server sends a fixed 64MiB random buffer to every client connection. It uses a 1 MiB write buffer.
ClientThe client spawns N concurrent goroutines (concurrency = 5, 10, 15...).
Each goroutine opens a TCP connection and reads until EOF using a 32 MiB buffer.
When running with 1 goroutine, the read time is longer.
As I increase concurrency to 5, 10, 15... the throughput of each individual goroutine improves significantly.
This happens even though:
CPU is not saturated
Network is not saturated
Disk is not involved
Both machines have very high bandwidth (10 GbE+)
Each goroutine should achieve similar throughput regardless of how many goroutines are running concurrently, assuming sufficient system resources.
Test code
1、server:
package main
import (
"bytes"
"fmt"
"math/rand"
"net"
"net/http"
_ "net/http/pprof"
"time"
"io"
)
const dataSize = 64 * 1024 * 1024 // 64 MiB
func main() {
go func() {
fmt.Println("pprof listening on :6060")
http.ListenAndServe("10.58.3.23:6060", nil)
}()
ln, err := net.Listen("tcp", "10.58.3.23:9090")
if err != nil {
panic(err)
}
fmt.Println("Server listening on :9090")
data := make([]byte, dataSize)
rand.Read(data)
for {
conn, err := ln.Accept()
if err != nil {
fmt.Println("Accept error:", err)
continue
}
go handleConn(conn, data)
}
}
func handleConn(conn net.Conn, data []byte) {
defer conn.Close()
fmt.Println("Client connected:", conn.RemoteAddr())
start := time.Now()
r := bytes.NewReader(data)
_, err := io.Copy(conn, r)
if err != nil {
fmt.Println("Write error:", err)
return
}
duration := time.Since(start)
fmt.Printf("Sent %d bytes to %v, duration: %v\n", dataSize, conn.RemoteAddr(), duration)
}
2、client code:
package main
import (
"fmt"
"io"
"net"
"sync"
"time"
)
const concurrency = 4
func main() {
var wg sync.WaitGroup
for i := 0; i < concurrency; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
start := time.Now()
conn, err := net.Dial("tcp", "10.58.3.23:9090")
if err != nil {
fmt.Printf("[Worker %d] Dial error: %v\n", id, err)
return
}
defer conn.Close()
buf := make([]byte, 64*1024*1024) // 1 MiB buffer
total := 0
for {
n, err := conn.Read(buf)
total += n
if err == io.EOF {
break
}
if err != nil {
fmt.Printf("[Worker %d] Read error: %v\n", id, err)
return
}
}
duration := time.Since(start)
fmt.Printf("[Worker %d] Finished reading %d bytes, duration: %v\n", id, total, duration)
}(i + 1)
}
wg.Wait()
fmt.Println("All goroutines completed")
}
On Nov 29, 2025, at 10:30 PM, doubled lin <lindo...@gmail.com> wrote:
Problem Description
--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/golang-nuts/f307dd0e-cc9d-434e-a452-8e367e987f3bn%40googlegroups.com.