Which HTTP Client Wins? Java FunTester vs Go net/http vs fasthttp Performance Test
The article presents a detailed performance comparison of three HTTP client implementations—Java FunTester, Go's net/http, and the high‑performance fasthttp library—across multiple thread counts and artificial latency settings, reporting CPU usage, memory consumption, and QPS to determine the most efficient choice.
Background
After publishing tutorials on Go HTTP client usage and six ways to implement a Go HTTP server, the author decided to benchmark the HTTP client performance of Java (using the FunTester framework) against two Go implementations: the standard net/http package and the third‑party github.com/valyala/fasthttp library.
Test Setup
Three server configurations were used: a plain no‑delay service, a service with 5 ms artificial delay, and a service with 10 ms delay. For each configuration the tests were run with 1, 5, 10, and 20 concurrent threads. The Java client runs on the FunTester framework, while the Go clients use goroutines and channels to issue requests.
Java FunTester Client
class HttpClientTest extends FunLibrary {
static final String uri = "http://localhost:12345/test/fun";
static final HttpRequestBase get = FunLibrary.getHttpGet(uri);
static final int thread = 10;
static final int times = 10000;
public static void main(String[] args) {
RUNUP_TIME = 0;
FunTester tester = new FunTester();
new Concurrent(tester, thread, DEFAULT_STRING).start();
}
private static class FunTester extends FixedThread<HttpRequestBase> {
FunTester() { super(get, times, true); }
protected void doing() throws Exception { FunLibrary.executeOnly(get); }
FixedThread clone() { return new FunTester(); }
}
}Go net/http Client
var key bool = false
const (
url = "http://localhost:8001/test/fun"
thread = 20
times = 10000
)
func TestPer(t *testing.T) {
get := funtester.Get(url, nil)
c := make(chan int)
start := time.Now().UnixMilli()
for i := 0; i < thread; i++ {
go func() {
sum := 0
for i := 0; i < times; i++ {
if key { break }
funtester.Response(get)
sum++
}
key = true
c <- sum
}()
}
total := 0
for i := 0; i < thread; i++ { total += <-c }
end := time.Now().UnixMilli()
diff := end - start
log.Printf("Total time: %f", float64(diff)/1000)
log.Printf("Requests: %d", total)
log.Printf("QPS: %f", float64(total)/float64(diff)*1000)
}Go fasthttp Client
var key bool = false
const (
url = "http://localhost:8001/test/fun"
thread = 20
times = 10000
)
func TestPerFast(t *testing.T) {
c := make(chan int)
start := time.Now().UnixMilli()
for i := 0; i < thread; i++ {
go func() {
sum := 0
for i := 0; i < times; i++ {
if key { break }
get := funtester.FastGet(url, nil)
funtester.FastResponse(get)
sum++
}
key = true
c <- sum
}()
}
total := 0
for i := 0; i < thread; i++ { total += <-c }
end := time.Now().UnixMilli()
diff := end - start
log.Printf("Total time: %f", float64(diff)/1000)
log.Printf("Requests: %d", total)
log.Printf("QPS: %f", float64(total)/float64(diff)*1000)
}Results
No‑delay service
1 thread – FunTester: 17,715 QPS, 51 % CPU, 355 MB RAM; net/http: 13,120 QPS, 104 % CPU, 15 MB RAM; fasthttp: 20,255 QPS, 82 % CPU, 5 MB RAM.
5 threads – FunTester: 59,626 QPS, 230 % CPU, 556 MB RAM; net/http: 43,143 QPS, 323 % CPU, 15 MB RAM; fasthttp: 68,659 QPS, 216 % CPU, 6 MB RAM.
10 threads – FunTester: 81,795 QPS, 356 % CPU, 685 MB RAM; net/http: 36,431 QPS, 573 % CPU, 1.36 GB RAM; fasthttp: 82,093 QPS, 322 % CPU, 7 MB RAM.
5 ms latency service
10 threads – FunTester: 1,671 QPS, 20 % CPU, 164 MB RAM; net/http: 1,440 QPS, 31 % CPU, 14 MB RAM; fasthttp: 1,709 QPS, 16 % CPU, 7 MB RAM.
20 threads – FunTester: 3,318 QPS, 37 % CPU, 235 MB RAM; net/http: 2,400 QPS, 48 % CPU, 14 MB RAM; fasthttp: 3,339 QPS, 33 % CPU, 7.5 MB RAM.
The patterns are consistent: fasthttp consistently delivers the highest QPS while using the least CPU and memory, especially under higher concurrency. The Java FunTester implementation is competitive with fasthttp in QPS but consumes far more memory. The standard net/http library lags behind both in QPS and, at higher thread counts, shows a steep increase in memory usage.
Conclusion
The github.com/valyala/fasthttp library proves to be the most efficient HTTP client for performance‑critical workloads, outperforming both the Java FunTester framework and Go's built‑in net/http in CPU, memory, and throughput. For Go‑based HTTP performance testing, the author recommends using fasthttp and skipping net/http.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
