【发布时间】:2013-10-16 16:11:52
【问题描述】:
我有一个应用程序,它使用HttpClient (4.1.3 or 4.2-beta) 从 62 个目标主机下载超过 4500 个 html 页面。它在 Windows 7 64 位上运行。处理器 - 酷睿 i7 2600K。网络带宽 - 54 Mb/s。
此时它使用这样的参数:
-
DefaultHttpClient和PoolingClientConnectionManager; - 还有
IdleConnectionMonitorThreadfromhttp://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html; - 最大总连接数 = 80;
- 每条路由的默认最大连接数 = 5;
- 对于线程管理,它使用具有并行性的
ForkJoinPool
level = 5(我是否正确理解它是一些工作
线程?)
在这种情况下,我的网络使用率(在 Windows 任务管理器中)没有超过 2.5%。下载 4500 个页面需要 70 分钟。在 HttpClient 日志中我有这样的事情:
调试 ForkJoinPool-2-worker-1 [org.apache.http.impl.conn.PoolingClientConnectionManager]:连接 发布:[id:209][路由:{}->http://stackoverflow.com][保留总数 活着:6;分配的路线:5 条中的 1 条;总分配:80 个中的 10 个]
分配的连接总数不会超过 10-12,尽管我已将其设置为 80 个连接。 如果我尝试将并行度提高到 20 或 80,网络使用率保持不变,但会产生很多连接超时。
我已阅读 hc.apache.org(HttpClient Performance Optimization Guide 和 HttpClient Threading Guide)上的教程,但它们没有帮助。
任务的代码如下所示:
public class ContentDownloader extends RecursiveAction {
private final HttpClient httpClient;
private final HttpContext context;
private List<Entry> entries;
public ContentDownloader(HttpClient httpClient, List<Entry> entries){
this.httpClient = httpClient;
context = new BasicHttpContext();
this.entries = entries;
}
private void computeDirectly(Entry entry){
final HttpGet get = new HttpGet(entry.getLink());
try {
HttpResponse response = httpClient.execute(get, context);
int statusCode = response.getStatusLine().getStatusCode();
if ( (statusCode >= 400) && (statusCode <= 600) ) {
logger.error("Couldn't get content from " + get.getURI().toString() + "\n" + response.toString());
} else {
HttpEntity entity = response.getEntity();
if (entity != null) {
String htmlContent = EntityUtils.toString(entity).trim();
entry.setHtml(htmlContent);
EntityUtils.consumeQuietly(entity);
}
}
} catch (Exception e) {
} finally {
get.releaseConnection();
}
}
@Override
protected void compute() {
if (entries.size() <= 1){
computeDirectly(entries.get(0));
return;
}
int split = entries.size() / 2;
invokeAll(new ContentDownloader(httpClient, entries.subList(0, split)),
new ContentDownloader(httpClient, entries.subList(split, entries.size())));
}
}
问题是 - 使用多线程 HttpClient 的最佳做法是什么,可能有一些设置 ConnectionManager 和 HttpClient 的规则?如何使用全部 80 个连接并提高网络使用率?
如有需要,我会提供更多代码。
【问题讨论】:
标签: java multithreading apache-httpclient-4.x