Java 如何在抓取大量小文件时优化HTTPClient性能?

Java 如何在抓取大量小文件时优化HTTPClient性能?,java,web-crawler,httpclient,Java,Web Crawler,Httpclient,我只想抓取一些黑客新闻故事和我的代码: import org.apache.http.client.fluent.Request; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; import java.util.logging.Logger; import java.util.stream.IntStream; public class HackCraw

我只想抓取一些黑客新闻故事和我的代码:

import org.apache.http.client.fluent.Request;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.logging.Logger;
import java.util.stream.IntStream;

public class HackCrawler {
    private static String getUrlResponse(String url) throws IOException {
        return Request.Get(url).execute().returnContent().asString();
    }

    private static String crawlItem(int id) {
        try {
            String json = getUrlResponse(String.format("https://hacker-news.firebaseio.com/v0/item/%d.json", id));
            if (json.contains("\"type\":\"story\"")) {
                return json;
            }
        } catch (IOException e) {
            System.out.println("crawl " + id + " failed");
        }
        return "";
    }

    public static void main(String[] args) throws FileNotFoundException {
        Logger logger = Logger.getLogger("main");
        PrintWriter printWriter = new PrintWriter("hack.json");
        for (int i = 0; i < 10000; i++) {
            logger.info("batch " + i);
            IntStream.range(12530671 - (i + 1) * 100, 12530671 - i * 100)
                    .parallel()
                    .mapToObj(HackCrawler::crawlItem).filter(x -> !x.equals(""))
                    .forEach(printWriter::println);
        }
    }
}
import org.apache.http.client.fluent.Request;
导入java.io.FileNotFoundException;
导入java.io.IOException;
导入java.io.PrintWriter;
导入java.util.logging.Logger;
导入java.util.stream.IntStream;
公共类爬虫{
私有静态字符串getUrlResponse(字符串url)引发IOException{
return Request.Get(url.execute().returnContent().asString();
}
私有静态字符串爬网项(int-id){
试一试{
String json=getUrlResponse(String.format(“https://hacker-news.firebaseio.com/v0/item/%d.json“,id));
if(json.contains(“\”type\:\”story\”){
返回json;
}
}捕获(IOE异常){
System.out.println(“爬网”+id+“失败”);
}
返回“”;
}
公共静态void main(字符串[]args)引发FileNotFoundException{
Logger Logger=Logger.getLogger(“主”);
PrintWriter PrintWriter=newprintWriter(“hack.json”);
对于(int i=0;i<10000;i++){
logger.info(“批次”+i);
IntStream.范围(12530671-(i+1)*10012530671-i*100)
.parallel()
.mapToObj(HackCrawler::crawleItem).filter(x->!x.equals(“”)
.forEach(printWriter::println);
}
}
}
现在,抓取100(1批)个项目需要3秒钟

我发现通过
并行
使用多线程可以提高速度(大约5倍),但我不知道如何进一步优化它


有谁能提出一些建议吗

以下步骤应该可以让您开始

  • 使用单个线程从站点获取响应,因为这基本上是一个IO操作
  • 将这些响应放入队列(了解BlockingQueue的各种实现)
  • 现在,您可以有多个线程来获取这些响应,并根据需要处理它们

  • 基本上,您将拥有一个生产者线程,从站点和处理这些响应的多个消费者那里获取响应。

    为了实现Fayaz的意思,我将使用Jetty Http客户端异步功能()

    该客户机在内部使用JavaNIO侦听传入的响应,每个连接只有一个线程。然后,它将内容分派给不涉及任何阻塞I/O操作的工作线程

    您可以尝试使用每个目的地的最大连接数(目的地基本上是主机)


    由于单个服务器的负载很重,这应该是相当高的。

    但是我已经通过
    parallel()
    尝试了多线程。。。通过BlockingQueue进行多线程处理是否会神奇地提高性能?在您的方法中,您正在生成多个线程,每个线程同时执行获取响应和处理响应的任务。我认为这不是推荐的方法。您的问题是典型的生产者-消费者问题。我已经查看了Jetty HttpClient的文档,但是我找不到任何关于连接管理的内容(我认为
    保持活动状态
    将提高性能),您对此有何想法?在HTTP 1.1中,默认情况下连接是持久的
    httpClient.newRequest("http://domain.com/path")
            .send(new Response.CompleteListener()
            {
                @Override
                public void onComplete(Result result)
                {
                    // Your logic here
                }
            });