On Thu, Apr 02, 2009 at 10:55:32AM +0200, Oleg Kalnichevski wrote:
> On Thu, Apr 02, 2009 at 10:42:38AM +0200, Gruntz,Dominik wrote:
> > Thanks for your help!
> > I tried to simplify my question and therefore omitted some details. 
> > Actually, the resource I am accessing has a body of length 0. It is 
> > generated by a Servlet.service method which does not return any data and 
> > simply sets the content length to zero.
> > 
> >    protected void service(HttpServletRequest req, HttpServletResponse res) 
> > { 
> >       System.out.println("request from 
> > "+req.getRemoteHost()+":"+req.getRemotePort());        
> >       res.setContentLength(0);
> >    }
> > 
> > Obviously, I measured the timings without the println statement. But with 
> > that statement enabled I see, that both HttpClient and HttpURLConnection 
> > reuse the same socket for their requests, thus they both have to read the 
> > whole content (although in my case this content has size 0) and they both 
> > reuse the connection (the method name connect on HttpURLConnection is 
> > misleading).
> > 
> > So still the question: why these timing differences? 
> > 
> 
> HttpClient (at least version 4.0) is known to be faster or as fast as
> HttpURLConnection. Development of HttpClient 3.x effectively ceased
> several years ago. 
> 
> Look for flaws in your benchmark, like accidentally leaving logging on.
> 
> Oleg
> 
> 



 ran a few benchmarks of my own using test code I can trust

HttpCore, the low level toolkit HttpClient 4.0 is based on, is about 20% faster 
than HttpURLConnection. HttpClient 4.0 is about 3% slower. Test code attached.

Oleg


==== Test code ====

--- TestHttpJRE ---

public class TestHttpJRE {

    public static void main(String[] args) throws Exception {
        if (args.length < 2) {
            System.out.println("Usage: <target URI> <no of requests>");
            System.exit(-1);
        }
        URI targetURI = new URI(args[0]);
        int n = Integer.parseInt(args[1]);
        
        URL url = targetURI.toURL();
        
        byte[] buffer = new byte[4096];
        
        long startTime;
        long finishTime;
        int successCount = 0;
        int failureCount = 0;
        String serverName = "unknown";
        long total = 0;
        long contentLen = 0;
        long totalContentLen = 0;
        
        startTime = System.currentTimeMillis();
        for (int i = 0; i < n; i++) {
            HttpURLConnection c = (HttpURLConnection) url.openConnection();
            c.connect();
            InputStream instream = c.getInputStream();
            try {
                contentLen = 0;
                if (instream != null) {
                    int l = 0;
                    while ((l = instream.read(buffer)) != -1) {
                        total += l;
                        contentLen += l;
                    }
                }
                if (c.getResponseCode() == 200) {
                    successCount++;
                } else {
                    failureCount++;
                }
                totalContentLen += contentLen;
            } catch (IOException ex) {
                failureCount++;
            }
            String s = c.getHeaderField("Server");
            if (s != null) {
                serverName = s;                
            }
        }
        finishTime = System.currentTimeMillis();
        
        float totalTimeSec = (float) (finishTime - startTime) / 1000;
        float reqsPerSec = (float) successCount / totalTimeSec; 
        float timePerReqMs = (float) (finishTime - startTime) / (float) 
successCount; 
        
        System.out.print("Server Software:\t");
        System.out.println(serverName);
        System.out.println();
        System.out.print("Document URI:\t\t");
        System.out.println(targetURI);
        System.out.print("Document Length:\t");
        System.out.print(contentLen);
        System.out.println(" bytes");
        System.out.println();
        System.out.print("Time taken for tests:\t");
        System.out.print(totalTimeSec);
        System.out.println(" seconds");
        System.out.print("Complete requests:\t");
        System.out.println(successCount);
        System.out.print("Failed requests:\t");
        System.out.println(failureCount);
        System.out.print("Content transferred:\t");
        System.out.print(total);
        System.out.println(" bytes");
        System.out.print("Requests per second:\t");
        System.out.print(reqsPerSec);
        System.out.println(" [#/sec] (mean)");
        System.out.print("Time per request:\t");
        System.out.print(timePerReqMs);
        System.out.println(" [ms] (mean)");
    }
    
}

--------------------

--- TestHttpCore ---
public class TestHttpCore {

    public static void main(String[] args) throws Exception {
        if (args.length < 2) {
            System.out.println("Usage: <target URI> <no of requests>");
            System.exit(-1);
        }
        URI targetURI = new URI(args[0]);
        int n = Integer.parseInt(args[1]);
        
        HttpHost targetHost = new HttpHost(
                targetURI.getHost(), 
                targetURI.getPort()); 
        
        BasicHttpParams params = new BasicHttpParams();
        params.setParameter(HttpProtocolParams.PROTOCOL_VERSION, 
                HttpVersion.HTTP_1_1);
        params.setBooleanParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, 
                false);
        params.setBooleanParameter(HttpConnectionParams.STALE_CONNECTION_CHECK, 
                false);
        params.setIntParameter(HttpConnectionParams.SOCKET_BUFFER_SIZE, 
                2 * 1024);
        
        BasicHttpRequest httpget = new BasicHttpRequest("GET", 
targetURI.getPath());

        byte[] buffer = new byte[4096];
        
        long startTime;
        long finishTime;
        int successCount = 0;
        int failureCount = 0;
        String serverName = "unknown";
        long total = 0;
        long contentLen = 0;
        long totalContentLen = 0;
        
        HttpRequestExecutor httpexecutor = new HttpRequestExecutor();
        BasicHttpProcessor httpproc = new BasicHttpProcessor(); 
        // Required protocol interceptors
        httpproc.addInterceptor(new RequestContent());
        httpproc.addInterceptor(new RequestTargetHost());
        // Recommended protocol interceptors
        httpproc.addInterceptor(new RequestConnControl());
        httpproc.addInterceptor(new RequestUserAgent());
        httpproc.addInterceptor(new RequestExpectContinue());
        
        HttpContext context = new BasicHttpContext();

        DefaultHttpClientConnection conn = new DefaultHttpClientConnection();

        DefaultConnectionReuseStrategy connStrategy = new 
DefaultConnectionReuseStrategy(); 
        
        startTime = System.currentTimeMillis();
        for (int i = 0; i < n; i++) {
            if (!conn.isOpen()) {
                Socket socket = new Socket(
                        targetHost.getHostName(), 
                        targetHost.getPort() > 0 ? targetHost.getPort() : 80);
                conn.bind(socket, params);
            }

            context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
            context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, targetHost);

            httpexecutor.preProcess(httpget, httpproc, context);
            HttpResponse response = httpexecutor.execute(httpget, conn, 
context);
            httpexecutor.postProcess(response, httpproc, context);
            
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                InputStream instream = entity.getContent();
                try {
                    contentLen = 0;
                    if (instream != null) {
                        int l = 0;
                        while ((l = instream.read(buffer)) != -1) {
                            total += l;
                            contentLen += l;
                        }
                    }
                    successCount++;
                    totalContentLen += contentLen;
                } catch (IOException ex) {
                    conn.shutdown();
                    failureCount++;
                } finally {
                    instream.close();
                }
            }
            if (!connStrategy.keepAlive(response, context)) {
                conn.close();
            }
            Header header = response.getFirstHeader("Server");
            if (header != null) {
                serverName = header.getValue();
            }
        }
        finishTime = System.currentTimeMillis();
        
        float totalTimeSec = (float) (finishTime - startTime) / 1000;
        float reqsPerSec = (float) successCount / totalTimeSec; 
        float timePerReqMs = (float) (finishTime - startTime) / (float) 
successCount; 
        
        System.out.print("Server Software:\t");
        System.out.println(serverName);
        System.out.println();
        System.out.print("Document URI:\t\t");
        System.out.println(targetURI);
        System.out.print("Document Length:\t");
        System.out.print(contentLen);
        System.out.println(" bytes");
        System.out.println();
        System.out.print("Time taken for tests:\t");
        System.out.print(totalTimeSec);
        System.out.println(" seconds");
        System.out.print("Complete requests:\t");
        System.out.println(successCount);
        System.out.print("Failed requests:\t");
        System.out.println(failureCount);
        System.out.print("Content transferred:\t");
        System.out.print(total);
        System.out.println(" bytes");
        System.out.print("Requests per second:\t");
        System.out.print(reqsPerSec);
        System.out.println(" [#/sec] (mean)");
        System.out.print("Time per request:\t");
        System.out.print(timePerReqMs);
        System.out.println(" [ms] (mean)");
    }
    
}
--------------------

--- TestHttpClient ---
public class TestHttpClient {

    public static void main(String[] args) throws Exception {
        if (args.length < 2) {
            System.out.println("Usage: <target URI> <no of requests>");
            System.exit(-1);
        }
        String targetURI = args[0];
        int n = Integer.parseInt(args[1]);
        
        BasicHttpParams params = new BasicHttpParams();
        params.setParameter(HttpProtocolParams.PROTOCOL_VERSION, 
                HttpVersion.HTTP_1_1);
        params.setBooleanParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, 
                false);
        params.setBooleanParameter(HttpConnectionParams.STALE_CONNECTION_CHECK, 
                false);
        params.setIntParameter(HttpConnectionParams.SOCKET_BUFFER_SIZE, 
                2 * 1024);
        
        DefaultHttpClient httpclient = new DefaultHttpClient(params);
        
        HttpGet httpget = new HttpGet(targetURI);

        byte[] buffer = new byte[4096];
        
        long startTime;
        long finishTime;
        int successCount = 0;
        int failureCount = 0;
        String serverName = "unknown";
        long total = 0;
        long contentLen = 0;
        long totalContentLen = 0;
        
        startTime = System.currentTimeMillis();
        for (int i = 0; i < n; i++) {
            HttpResponse response = httpclient.execute(httpget);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                InputStream instream = entity.getContent();
                try {
                    contentLen = 0;
                    if (instream != null) {
                        int l = 0;
                        while ((l = instream.read(buffer)) != -1) {
                            total += l;
                            contentLen += l;
                        }
                    }
                    successCount++;
                    totalContentLen += contentLen;
                } catch (IOException ex) {
                    httpget.abort();
                    failureCount++;
                } finally {
                    instream.close();
                }
            }
            Header header = response.getFirstHeader("Server");
            if (header != null) {
                serverName = header.getValue();
            }
        }
        finishTime = System.currentTimeMillis();
        
        float totalTimeSec = (float) (finishTime - startTime) / 1000;
        float reqsPerSec = (float) successCount / totalTimeSec; 
        float timePerReqMs = (float) (finishTime - startTime) / (float) 
successCount; 
        
        System.out.print("Server Software:\t");
        System.out.println(serverName);
        System.out.println();
        System.out.print("Document URI:\t\t");
        System.out.println(targetURI);
        System.out.print("Document Length:\t");
        System.out.print(contentLen);
        System.out.println(" bytes");
        System.out.println();
        System.out.print("Time taken for tests:\t");
        System.out.print(totalTimeSec);
        System.out.println(" seconds");
        System.out.print("Complete requests:\t");
        System.out.println(successCount);
        System.out.print("Failed requests:\t");
        System.out.println(failureCount);
        System.out.print("Content transferred:\t");
        System.out.print(total);
        System.out.println(" bytes");
        System.out.print("Requests per second:\t");
        System.out.print(reqsPerSec);
        System.out.println(" [#/sec] (mean)");
        System.out.print("Time per request:\t");
        System.out.print(timePerReqMs);
        System.out.println(" [ms] (mean)");
    }
    
}

--------------------

==== Test results ====

--- TestHttpJRE ---

Server Software:        Apache-Coyote/1.1

Document URI:           
http://localhost:8080/servlets-examples/servlet/RequestInfoExample
Document Length:        689 bytes

Time taken for tests:   9.047 seconds
Complete requests:      20000
Failed requests:        0
Content transferred:    13780000 bytes
Requests per second:    2210.6775 [#/sec] (mean)
Time per request:       0.45235 [ms] (mean)

--------------------

--- TestHttpCore ---

Server Software:        Apache-Coyote/1.1

Document URI:           
http://localhost:8080/servlets-examples/servlet/RequestInfoExample
Document Length:        689 bytes

Time taken for tests:   7.031 seconds
Complete requests:      20000
Failed requests:        0
Content transferred:    13780000 bytes
Requests per second:    2844.5454 [#/sec] (mean)
Time per request:       0.35155 [ms] (mean)

--------------------

--- TestHttpClient ---

Server Software:        Apache-Coyote/1.1

Document URI:           
http://localhost:8080/servlets-examples/servlet/RequestInfoExample
Document Length:        689 bytes

Time taken for tests:   9.282 seconds
Complete requests:      20000
Failed requests:        0
Content transferred:    13780000 bytes
Requests per second:    2154.7083 [#/sec] (mean)
Time per request:       0.4641 [ms] (mean)
--------------------

> 
> > Thanks for any further advice.
> > 
> > Best wishes
> > Dominik
> > 
> > 
> > -----Original Message-----
> > From: Oleg Kalnichevski [mailto:[email protected]] 
> > Sent: Donnerstag, 2. April 2009 09:50
> > To: HttpClient User Discussion
> > Subject: Re: HttpClient performance
> > 
> > On Thu, Apr 02, 2009 at 01:54:56AM +0200, Gruntz,Dominik wrote:
> > > Hi,
> > > I wrote a method which requests a resource several times from on a 
> > > servlet server (on localhost). 
> > > It seems to me that the version using HttpClient is abouot a factor of 
> > > 20-30 slower than the 
> > > version based on Sun's HttpURLConnection. I cannot believe these figures 
> > > and ask you, where 
> > > I misused the HttpClient class. If the result is correct, what is the 
> > > reasen that HttpClient
> > > is slower?
> > > 
> > > The HttpClient method looks as follows:
> > > 
> > >   static void doJakartaCommons(String path) throws Exception {
> > >           HttpClient client = new HttpClient();
> > >           for (int i = 0; i < 1000; i++) {
> > >                   HttpMethod method = new GetMethod(path);
> > >                   client.executeMethod(method);
> > >                   int code = method.getStatusCode();
> > >                   if(code != 200)
> > >                           throw new IllegalStateException();
> > >                   method.releaseConnection();
> > >           }
> > >   }
> > > 
> > > 
> > > The version bsaed on HttpURLConnection looks as follows:
> > > 
> > >   static void doHttpConnection(String path) throws Exception {
> > >           for (int i = 0; i < 1000; i++) {
> > >                   URL url = new URL(path);
> > >                   HttpURLConnection c = (HttpURLConnection) 
> > > url.openConnection();
> > >                   c.connect();
> > >                   int code = c.getResponseCode();
> > >                   if(code != 200)
> > >                           throw new IllegalStateException();
> > >           }
> > >   }
> > > 
> > > 
> > > Thanks for your help.
> > > Dominik
> > > 
> > > 
> > 
> > Your performance benchmark is completely flawed. You are comparing
> > apples to oranges. Here's what HttpURLConnection test does: open a
> > connection, execute request, read response head, drop connection. Here's
> > what your HttpClient test case does: open a connection, execute request,
> > read response head, read response body (!!!!), re-use connection.
> > Obviously opening a new local connection is significantly faster than
> > reading a larger response body
> > 
> > Performance benchmarking is a tricky business.
> > 
> > Oleg
> > 
> > 
> > 
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: [email protected]
> > For additional commands, e-mail: [email protected]
> > 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [email protected]
> For additional commands, e-mail: [email protected]
> 

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to