【问题标题】:Parallelizing many GET requests并行化许多 GET 请求
【发布时间】:2013-07-31 13:26:01
【问题描述】:

有没有什么有效的方法可以并行处理 Java 中的大量 GET 请求。我有一个包含 200,000 行的文件,每行都需要来自 Wikimedia 的 GET 请求。然后我必须将响应的一部分写入一个公共文件。我已将代码的主要部分粘贴在下面作为参考。

while ((line = br.readLine()) != null) {
    count++;
    if ((count % 1000) == 0) {
        System.out.println(count + " tags parsed");
        fbw.flush();
        bw.flush();
    }
    //System.out.println(line);
    String target = new String(line);
    if (target.startsWith("\"") && (target.endsWith("\""))) {
        target = target.replaceAll("\"", "");
    }
    String url = "http://en.wikipedia.org/w/api.php?action=query&prop=revisions&format=xml&rvprop=timestamp&rvlimit=1&rvdir=newer&titles=";
    url = url + URLEncoder.encode(target, "UTF-8");
    URL obj = new URL(url);
    HttpURLConnection con = (HttpURLConnection) obj.openConnection();
    // optional default is GET
    con.setRequestMethod("GET");
    //add request header
    //con.setRequestProperty("User-Agent", USER_AGENT);
    int responsecode = con.getResponseCode();
    //System.out.println("Sending 'Get' request to URL: " + url);
    BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
    String inputLine;
    StringBuffer response = new StringBuffer();
    while ((inputLine = in.readLine()) != null) {
        response.append(inputLine);         
    }
    Document doc = loadXMLFromString(response.toString());
    NodeList x = doc.getElementsByTagName("revisions");
    if (x.getLength() == 1) {
        String time = x.item(0).getFirstChild().getAttributes().item(0).getTextContent().substring(0,10).replaceAll("-", "");
        bw.write(line + "\t" + time + "\n");
    } else if (x.getLength() == 2) {
        String time = x.item(1).getFirstChild().getAttributes().item(0).getTextContent().substring(0, 10).replaceAll("-", "");          
        bw.write(line + "\t" + time + "\n");
    } else {
        fbw.write(line + "\t" + "NULL" + "\n");
    }
}

我搜索了一下,似乎有两种选择。一种是创建线程,另一种是使用称为 Executor 的东西。有人可以就哪一个更适合这项任务提供一些指导吗?

【问题讨论】:

  • 使用Executor,这是使用线程的更简单方法。还可以考虑使用专用库通过重用连接来最小化 TCP 开销。
  • 有效的问题,但是对于这么多的请求,您可能只考虑downloading the wikipedia database 而不是逐个请求?他们不一定是like web crawlers

标签: java multithreading get parallel-processing httprequest


【解决方案1】:

如上所述,您应该根据服务器的容量确定并行 GET 请求的数量。如果您想坚持使用 JVM 但又想使用 Groovy,这里有一个非常简短的并行 GET 请求示例。

最初有一个您要获取的 URL 列表。 完成后,任务列表包含可通过 get() 方法访问的所有结果,以供以后处理。这里只是打印出来的例子。

import groovyx.net.http.AsyncHTTPBuilder

def urls = [
  'http://www.someurl.com',
  'http://www.anotherurl.com'
]
AsyncHTTPBuilder http = new AsyncHTTPBuilder(poolSize:urls.size())
def tasks = []
urls.each{
  tasks.add(http.get(uri:it) { resp, html -> return html })
}
tasks.each { println it.get() }

请注意,对于生产环境,您需要处理超时、错误响应等问题。

【讨论】:

    【解决方案2】:

    如果您真的需要通过 GET 请求来完成,我建议您使用带有 small 线程池(2 或 3)的 ThreadPoolExecutor 以避免维基百科服务器过载。这将避免大量的编码......

    还可以考虑使用 Apache HttpClient 库(具有持久连接!)。


    但使用数据库下载选项更好。根据您的操作,您可以选择其中一种较小的下载。 This page 讨论了各种选项。

    注意:维基百科更喜欢人们下载数据库转储(等等)而不是冲击他们的网络服务器。

    【讨论】:

      【解决方案3】:

      你需要做的是:

      1. 有一个生产者线程读取每一行并将其添加到队列中。
      2. 有一个ThreadPool,其中每个线程都接受一个 URL 并执行 GET 请求
      3. 它获取响应并将其添加到队列中。
      4. 还有一个消费者线程,用于检查队列并将其添加到文件中。

      【讨论】:

        猜你喜欢
        • 2021-07-31
        • 2023-04-02
        • 1970-01-01
        • 1970-01-01
        • 2011-08-06
        • 1970-01-01
        • 2022-10-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多