3

を使用して、62 のターゲット ホストから 4500 を超える html ページをダウンロードするアプリケーションがありますHttpClient (4.1.3 or 4.2-beta)。Windows 7 64 ビットで動作します。プロセッサ - コア i7 2600K。ネットワーク帯域幅 - 54 Mb/秒。

現時点では、次のようなパラメーターを使用しています。

  • DefaultHttpClientそしてPoolingClientConnectionManager;
  • また、から持っていIdleConnectionMonitorThreadます
    http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html
  • 最大合計接続数 = 80;
  • ルートごとのデフォルトの最大接続数 = 5;
  • スレッド管理にはForkJoinPool、並列度=5で使用しています(作業 スレッド
    数だと正しく理解できていますか?)

この場合、(Windows タスク マネージャーでの) ネットワーク使用率は 2.5% を超えません。4500 ページをダウンロードするには 70 分かかります。そして、HttpClient ログには次のようなものがあります。

DEBUG ForkJoinPool-2-worker-1 [org.apache.http.impl.conn.PoolingClientConnectionManager]: 接続が解放されました: [id: 209][ルート: {}->http://stackoverflow.com][合計キープアライブ: 6; 割り当てられたルート: 1/5; 割り当てられた合計: 10/80]

割り当てられた接続の合計は、最大 80 接続に設定したにもかかわらず、10-12 を超えません。並列処理レベルを 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 接続すべてを使用してネットワーク使用率を上げるにはどうすればよいですか?

必要に応じて、さらにコードを提供します。

4

3 に答える 3

4

プルしているホストの数はわかりませんが、数が少ない(または1つだけ)場合は、ルートあたりの最大数を増やします。これにより、ホストごとの同時実行性が向上します。

現在、5に設定されています。最大接続使用量が最大10〜12であることが確認されています。おそらく、2〜3の異なるホストにしかヒットしていません。この場合、計算は合計されます。

于 2012-09-22T21:16:27.993 に答える
0

Apache HttpClientは、ループバックインターフェイスでも帯域幅を飽和させるのに十分な速度である必要があります。パフォーマンスの問題は、コンテンツの取得よりもコンテンツの処理の効率に関係しているのではないかと思います。アプリケーションは、新しいページをダウンロードするよりもHTMLコンテンツの処理とリンクの抽出に多くの時間を費やしているため、帯域幅が十分に活用されていません。コードが処理前にHTMLコンテンツを文字列に変換するという事実でさえ、アプリケーションがネットワークを介してデータを転送するよりも、メモリ内のデータをコピーすることに多くの時間を費やしていると私は信じています。

于 2012-05-21T12:59:55.713 に答える