繁体   English   中英

为什么 Java HTTP 请求这么慢(与 Python 相比),我怎样才能让它们更快?

[英]Why are Java HTTP requests so slow (in comparison to Python), and how can I make them faster?

Java 是一门漂亮的语言,据说效率也很高。 来自使用过 Python 的背景,我想看看这两种语言之间的区别——从一开始我就对 Java 基于 OOP 的语法的明确性和清晰度印象深刻。 但是,我还想测试语言之间的性能差异。

我首先尝试通过计算速度测试两种语言之间的性能差异。 为此,我用每种语言编写了一些代码——程序试图计算一个数学问题,并且会迭代很多次。 我不会在这里添加此代码,但我会说结果 - Python 几乎比 Java 慢 2 倍(按时间测量)。 有趣,但这是意料之中的。 毕竟,我想尝试使用 Java 的全部原因是因为有很多人吹嘘计算速度。

之后,我进行了第二次测试——将 HTTP 连接到网站,以下载 web 页面。 对于这个测试,我编写了另一个测试程序,它的作用与上一个测试相同,除了不计算数学方程式,它将使用 HTTP 库下载 web 页面。

我最终在 Python 中编写了以下脚本。 这非常简单,它在下载 web 页面时迭代 10 次,然后打印平均值。

from requests import get
from time import time

# Start the timer
start = time()

# Loop 10 times
for i in range(10):
    # Execute GET request
    get("https://httpbin.org/get")

# Stop the timer
stop = time()

# Calculate and print average
avg = (stop - start) / 10

print(avg)
# Prints 0.5385, on my system.

对于 Java 测试,我编写了以下代码。 它与之前的测试相同,但在 Java 中实现。

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

import java.io.IOException;
import java.util.Objects;

public class Test {

    public static String run(String url) throws IOException {
        // Code taken from OKHTTP docs
        // https://square.github.io/okhttp/
        // https://raw.githubusercontent.com/square/okhttp/master/samples/guide/src/main/java/okhttp3/guide/GetExample.java
        OkHttpClient client = new OkHttpClient();

        Request request = new Request.Builder()
            .url(url)
            .build();

        try (Response response = client.newCall(request).execute()) {
            return Objects.requireNonNull(response.body()).string();
        }
    }

    public static void main(String[] args) throws IOException {
        // Start the timer
        long startTime = System.nanoTime();

        // Loop 10 times
        for (int i = 0; i < 10; i++) {
            // Execute GET request
            run("https://httpbin.org/get");
        }

        // Stop the timer
        long endTime = System.nanoTime();

        // Calculate the average
        float average = (((float) (endTime - startTime)) / 1000000000) / 10;

        // Print results (1.05035 on my system)
        System.out.println(average);
    }
}

呃……没想到。 唉,Java 不应该比 Python 快吗? 我很震惊地看到 Java 在这个测试中比 Python 慢了几乎 2 倍,但我决心找到一个有利于 ZD52387880E1EA22817A72D37592138 的结论。 为了满足这一点,我决定使用 Java 默认库而不是OkHttp库重新编写测试。 我不会在这里显示代码,因为它很长,但我使用了HttpURLConnection来帮助我。 我的结果还是一样,但比OkHttp库要快一些。

我的最终测试与之前的测试相同,但在http://网站上进行(以防由于 SSL 连接而出现缓慢)。 我的结果还是一样——Python 快了将近 2 倍。 The only thing I could think of to why this is happening is because the requests Python library would be coded in C, but as you can see from the "Languages" section of their GitHub page , all of the requests library was programmed in pure Python .

我想了解为什么 Java 在运行 HTTP 连接时如此缓慢,如果我的系统设置或 Java 测试代码有问题,我应该写什么来改进结果? 此外,如果可能的话,如何发送 Java HTTP 请求,使其比 Python requests对应的请求更快?

我真的对你得到的结果持怀疑态度,所以我尝试使用与你完全相同的 Python 代码和main Java 方法(使用 https)。
这是读取响应的整个 JSON 内容的 Java run方法:

private static String run(String url) throws IOException {
    final URLConnection c = new URL(url).openConnection();
    c.connect();
    try (InputStream is = c.getInputStream()) {
        final byte[] buf = new byte[1024];
        final StringBuilder b = new StringBuilder();
        int read = 0;
        while ((read = is.read(buf)) != -1) {
            b.append(new String(buf, 0, read));
        }
        return b.toString();
    }
}

我的系统上的结果:

  • Python 2.7.12:0.5117351770401001
  • Python 3.5.2:0.48344600200653076
  • Java 1.8:0.19684727

10 次迭代可能不足以得到一个好的结果,但在这里,Java 至少快了 2 倍。

TLDR:

请求的大部分生命周期都花在了实际的互联网流量中。 尽管 Java 比 Python 快,但每个请求只能缩短几毫秒,因为记录 1 个请求的大部分时间是由于服务器延迟/延迟。 此外,重用 Python Session和 Java OkHttpClient对象,以选择加入关键优化,从而缩短计算时间。


我在帖子中犯了一些错误。 第一个是我为每个请求生成一个新的OkHttpClient object 并直接使用get方法。 正如 Jesse 在评论中指出的那样,通过使用这些,我错过了重度优化,因此得到了不公平的结果。

为了解决这个问题,我使用了Session object 来保存我的请求历史记录,并同样保存了相同的OkHttpClient object。

我在 Python 中实现的改进:

from requests import Session
from time import time

# Start the timer
start = time()

# Create a new Session     <-----
s = Session()

# Loop a few times
for i in range(50):
    # Execute GET request
    s.get("http://httpbin.org/get")

# Stop the timer
stop = time()

# Calculate and print average
avg = (stop - start) / 50

print(avg) # 180ms on my system

同样,我在 Java 中使用基本的 Singleton class 和 OkHttp 库顶部的一些包装类实现了相同的概念。 我不会在这里发布整个代码,因为我决定将它扩展到许多类,但基本思想很简单。 在进行这些更改并记录我新发现的统计数据后,我得到了以下图表:

统计数据

如图所示,Python 实际上对执行的第一个请求有更快的初始化过程。 但是,您还可以注意到,对于平均请求(50 个连续和同步请求的平均值),Java 库( URLConnectionOkHttp )与 Python requests库相比减少了几毫秒。

概括:

By reusing the Python Session and Java OkHttpClient objects ( initialize the object once and use it for all requests, instead of making a new one for each request ), heavy optimizations are done, and therefore the execution times are drastically lowered. 然而,就平均值而言,Java 仅比 Python 高出几毫秒,因为请求期间花费的大部分时间来自网络传输时间(通过 Internet 在计算机之间发送数据所需的时间)。

如果有人想评论更多信息或在另一个答案中展示他们自己的发现,我会欣喜若狂地阅读更多相关信息。 感谢那些对我的问题发表评论并帮助我找出优化过程的一些关键组成部分的人。 万岁Java :)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM