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.

FunTester
FunTester
FunTester
Which HTTP Client Wins? Java FunTester vs Go net/http vs fasthttp Performance Test

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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaperformanceGoHTTPBenchmarknet/httpfasthttp
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.