web-dev-qa-db-fra.com

Méthode recommandée pour utiliser HttpClient dans un environnement multithread

Cela fait un moment que j'utilise HttpClient dans un environnement multithread. Pour chaque thread, lorsqu'il crée une connexion, il crée une toute nouvelle instance HttpClient.

Récemment, j'ai découvert qu'en utilisant cette approche, trop de ports pouvaient être ouverts par l'utilisateur et la plupart des connexions étaient à l'état TIME_WAIT.

http://www.opensubscriber.com/message/[email protected]/86045.html

Par conséquent, au lieu que chaque thread fasse:

HttpClient c = new HttpClient();
try {
    c.executeMethod(method);
}
catch(...) {
}
finally {
    method.releaseConnection();
}

Nous prévoyons d'avoir:

[MÉTHODE A]

// global_c is initialized once through
// HttpClient global_c = new HttpClient(new MultiThreadedHttpConnectionManager());

try {
    global_c.executeMethod(method);
}
catch(...) {
}
finally {
    method.releaseConnection();
}

Dans une situation normale, global_c sera accessible simultanément par 50 threads ++. Je me demandais si cela créerait des problèmes de performances? MultiThreadedHttpConnectionManager utilise-t-il un mécanisme sans verrouillage pour implémenter sa stratégie de sécurité des threads?

Si 10 threads utilisent global_c, les 40 autres threads seront-ils verrouillés?

Ou serait-il préférable que, dans chaque thread, je crée une instance d'un HttpClient, mais que je libère explicitement le gestionnaire de connexions?

[MÉTHODE B]

MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManager();
HttpClient c = new HttpClient(connman);
try {
      c.executeMethod(method);
}
catch(...) {
}
finally {
    method.releaseConnection();
    connman.shutdown();
}

Connman.shutdown () rencontrera-t-il des problèmes de performances?

Puis-je savoir quelle méthode (A ou B) est la meilleure, pour une application utilisant un thread 50 ++?

82
Cheok Yan Cheng

La méthode A est recommandée par la communauté de développeurs httpclient.

Veuillez vous référer à http://www.mail-archive.com/[email protected]/msg02455.html pour plus de détails.

17
Cheok Yan Cheng

Certainement la méthode A parce que son pool et son thread-safe.

Si vous utilisez httpclient 4.x, le gestionnaire de connexions s'appelle ThreadSafeClientConnManager . Voir ceci lien pour plus de détails (allez jusqu'à "Gestionnaire de connexions en pool"). Par exemple:

    HttpParams params = new BasicHttpParams();
    SchemeRegistry registry = new SchemeRegistry();
    registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
    ClientConnectionManager cm = new ThreadSafeClientConnManager(params, registry);
    HttpClient client = new DefaultHttpClient(cm, params);
43
user308808

Mon interprétation de la documentation est que HttpConnection en elle-même n'est pas traitée comme un thread-safe et que, par conséquent, MultiThreadedHttpConnectionManager fournit un pool réutilisable de HttpConnections, vous disposez d'un seul MultiThreadedHttpConnectionManager partagé par tous les threads et initialisé exactement une fois. Vous avez donc besoin de quelques petites améliorations pour l’option A.

MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManag

Ensuite, chaque thread devrait utiliser la séquence pour chaque requête, obtenir une connexion du pool et la remettre à la fin de son travail. Il peut être utile d’utiliser un bloc finale. Vous devez également coder pour la possibilité que le pool ne dispose pas de connexions disponibles et traiter l'exception de délai d'attente.

HttpConnection connection = null
try {
    connection = connman.getConnectionWithTimeout(
                        HostConfiguration hostConfiguration, long timeout) 
    // work
} catch (/*etc*/) {/*etc*/} finally{
    if ( connection != null )
        connman.releaseConnection(connection);
}

Comme vous utilisez un pool de connexions, vous ne fermerez pas réellement les connexions. Cela ne devrait donc pas poser le problème TIME_WAIT. Cette approche suppose que chaque thread ne reste pas longtemps sur la connexion. Notez que conman lui-même est laissé ouvert.

13
djna

Je pense que vous voudrez utiliser ThreadSafeClientConnManager.

Vous pouvez voir comment cela fonctionne ici: http://foo.jasonhudgins.com/2009/08/http-connection-reuse-in-Android.html

Ou dans le AndroidHttpClient qui l'utilise en interne.

5
Thomas Ahle

Avec HttpClient 4.5, vous pouvez faire ceci:

CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(new PoolingHttpClientConnectionManager()).build();

Notez que celui-ci implémente Closeable (pour fermer le gestionnaire de connexions).

2
Dimitar II