【问题标题】:what makes Jsoup faster than HttpURLConnection & HttpClient in most cases在大多数情况下,是什么让 Jsoup 比 HttpURLConnection 和 HttpClient 更快
【发布时间】:2020-01-31 17:04:22
【问题描述】:

我想比较标题中提到的三种实现的性能,我写了一个小 JAVA 程序来帮助我这样做。 main 方法包含三个测试块,每个块看起来像这样:

        nb=0; time=0;
        for (int i = 0; i < 7; i++) {
            double v = methodX(url);
            if(v>0){
                nb++;
                time+=v;
            }
        }
        if(nb==0) nb=1;
        System.out.println("HttpClient : "+(time/ ((double) nb))+". Tries "+nb+"/7");

变量nb 用于避免失败的请求。现在方法methodX 是其中之一:

    private static double testWithNativeHUC(String url){
        try {
            HttpURLConnection httpURLConnection= (HttpURLConnection) new URL(url).openConnection();
            httpURLConnection.addRequestProperty("User-Agent", UA);
            long before = System.currentTimeMillis();
            BufferedReader bufferedReader= new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()));
            while (bufferedReader.readLine()!=null);
            return System.currentTimeMillis()-before;
        } catch (IOException e) {
            e.printStackTrace();
            return -1;
        }
    }

    private static double testWithHC(String url) {
        try {
            CloseableHttpClient httpClient = HttpClientBuilder.create().setUserAgent(UA).build();
            BasicResponseHandler basicResponseHandler = new BasicResponseHandler();
            long before = System.currentTimeMillis();
            CloseableHttpResponse response = httpClient.execute(new HttpGet(url));
            basicResponseHandler.handleResponse(response);
            return System.currentTimeMillis() - before;
        } catch (IOException e) {
            e.printStackTrace();
            return -1;
        }
    }

    private static double testWithJsoup(String url){
        try{
            long before = System.currentTimeMillis();
            Jsoup.connect(url).execute().parse();
            return System.currentTimeMillis()-before;
        }catch (IOException e){
            e.printStackTrace();
            return -1;
        }
    }

我得到的输出如下。

对于网址https://stackoverflow.com

    HttpUrlConnection : 325.85714285714283. Tries 7/7
    HttpClient : 299.0. Tries 7/7
    Jsoup : 172.42857142857142. Tries 7/7

对于网址https://online.vfsglobal.dz

    HttpUrlConnection : 104.57142857142857. Tries 7/7
    HttpClient : 181.0. Tries 7/7
    Jsoup : 57.857142857142854. Tries 7/7

对于网址https://google.com/

    HttpUrlConnection : 251.28571428571428. Tries 7/7
    HttpClient : 259.57142857142856. Tries 7/7
    Jsoup : 299.85714285714283. Tries 7/7

对于网址https://algeria.blsspainvisa.com/book_appointment.php

    HttpUrlConnection : 112.57142857142857. Tries 7/7
    HttpClient : 194.85714285714286. Tries 7/7
    Jsoup : 67.42857142857143. Tries 7/7

对于网址https://tunisia.blsspainvisa.com/book_appointment.php

    HttpUrlConnection : 439.2857142857143. Tries 7/7
    HttpClient : 283.42857142857144. Tries 7/7
    Jsoup : 144.71428571428572. Tries 7/7

即使重复测试也会得到相同的结果,我没有在请求之间使用睡眠时间来获得快速结果,我相信它对结果没有太大影响。

编辑 事实上,我分析了 Jsoup 的来源,它表明它使用 HttpURLConnection 和 BufferedInputStream,我尝试以 HttpURLConnection 方式使用两者,但结果相同,正如你所看到的,区别很明显,Jsoup 似乎明显快于 HttpURLConnection它使用 HttpURLConnection !

提前致谢,

【问题讨论】:

  • 没什么。该代码仅与网络和服务器响应以及任何中间缓存一样快。客户的选择不会影响任何这些事情。重新检查您的数据并检查您的假设。
  • 事实上我分析了 Jsoup 的来源,它表明它使用 HttpURLConnection 和 BufferedInputStream,我尝试以 HttpURLConnection 方式使用两者,但结果相同,如您所见,区别很明显, Jsoup 似乎明显比 HttpURLConnection 快,它使用 HttpURLConnection !
  • 很抱歉,您的基准没有意义。未考虑 Java 中的某些因素(JIT、GC、内存分配……)。将顺序更改为 Jsoup、HttpClient、HttpUrlConnection 时,可能结果会有所不同。尝试 JHM 等微基准框架并进行更多尝试。

标签: java optimization jsoup httpclient httpurlconnection


【解决方案1】:

您的基准没有意义。

我为这三个库编写了一个微基准测试结果,没有显着差异。

Benchmark                                     Mode  Cnt    Score   Error  Units
HttpBenchmark.httpClientGoogle                avgt    2  151.162          ms/op
HttpBenchmark.httpClientStackoverflow         avgt    2  151.086          ms/op
HttpBenchmark.httpUrlConnectionGoogle         avgt    2  235.869          ms/op
HttpBenchmark.httpUrlConnectionStackoverflow  avgt    2  145.162          ms/op
HttpBenchmark.jsoupGoogle                     avgt    2  391.162          ms/op
HttpBenchmark.jsoupStackoverflow              avgt    2  188.059          ms/op

你的测试和我的只有一点不同:

  • JSoup 设置标头“Accept-Encoding”、“gzip”这将减少带宽
  • JSoup 使用更大的缓冲区 (32kb)
  • 需要重用HttpClient

在我的测试中,JSoup 是最慢的。当然只有 JSoup 会解析响应。

我的基准:

@Warmup(iterations = 1, time = 3, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 2, time = 5, timeUnit = TimeUnit.SECONDS)
@Fork(1)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@State(Scope.Benchmark)
@Threads(1)
public class HttpBenchmark {

    private static final String GOOGLE          = "https://google.com/";
    private static final String STACKOVERFLOW   = "https://stackoverflow.com";

    private final CloseableHttpClient httpClient = HttpClientBuilder.create().build();

    @Benchmark
    public void httpClientGoogle() throws Exception {
        httpClient(GOOGLE);
    }

    @Benchmark
    public void httpClientStackoverflow() throws Exception {
        httpClient(STACKOVERFLOW);
    }

    @Benchmark
    public void httpUrlConnectionGoogle() throws Exception {
        httpUrlConnection(GOOGLE);
    }

    @Benchmark
    public void httpUrlConnectionStackoverflow() throws Exception {
        httpUrlConnection(STACKOVERFLOW);
    }

    @Benchmark
    public void jsoupGoogle() throws Exception {
        jsoup(GOOGLE);
    }

    @Benchmark
    public void jsoupStackoverflow() throws Exception {
        jsoup(STACKOVERFLOW);
    }

    private void httpClient(final String url) throws Exception {
        final CloseableHttpResponse response = httpClient.execute(new HttpGet(url));
        final BasicResponseHandler basicResponseHandler = new BasicResponseHandler();
        basicResponseHandler.handleResponse(response);
        response.close();
    }

    private void httpUrlConnection(final String url) throws Exception {
        final HttpURLConnection httpURLConnection = (HttpURLConnection) new URL(url).openConnection();
        httpURLConnection.addRequestProperty("Accept-Encoding", "gzip");
        try (final BufferedInputStream r = new BufferedInputStream(httpURLConnection.getInputStream())) {
            final byte[] tmp = new byte[1024 * 32];
            int read;
            while (true) {
                read = r.read(tmp);
                if (read == -1) {
                    break;
                }
            }
        }
    }

    private void jsoup(final String url) throws Exception {
        Jsoup.connect(url).execute().parse();
    }

}

【讨论】:

  • 你能告诉我你用什么来做这些测试吗?我想用它做更多的测试
  • 我发现它是JMH,我会做更多测试,感谢基准测试的想法
  • 太好了,如果你能接受我的回答就太好了
  • 即使通过测试更多案例我发现相同的结果,对于我测试的大多数网站,Jsoup 都比 HUC 快,我认为这是 Jsoup 为 HUC 所做的一些优化的二重奏,例如连接持续(原因在测试时,许多请求被发送到同一个网站)我在我的 HUC 测试中没有使用,但不确定 JSoup 是否正在使用它
猜你喜欢
  • 1970-01-01
  • 2011-04-20
  • 2020-08-12
  • 2014-09-13
  • 1970-01-01
  • 2012-08-01
  • 1970-01-01
  • 2017-04-07
  • 1970-01-01
相关资源
最近更新 更多