2009-08-15 8 views
78

Per un po 'di tempo, ho utilizzato HttpClient in un ambiente con multithreading. Per ogni thread, quando avvia una connessione, creerà un'istanza HttpClient completamente nuova.Best practice per l'utilizzo di HttpClient in ambiente con multithreading

Recentemente, ho scoperto che, utilizzando questo approccio, può causare l'apertura di troppe porte e la maggior parte delle connessioni sono nello stato TIME_WAIT.

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

Quindi, invece di ogni thread fare:

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

Abbiamo in programma di avere:

[METODO A]

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

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

In una situazione normale, global_c sarà possibile accedere contemporaneamente a thread da 50 ++. Mi stavo chiedendo, questo creerà problemi di prestazioni? MultiThreadedHttpConnectionManager utilizza un meccanismo di blocco per implementare la relativa politica di sicurezza thread?

Se 10 thread utilizzano global_c, gli altri 40 thread saranno bloccati?

O sarebbe meglio se, in ogni thread, creo un'istanza di un HttpClient, ma rilasci esplicitamente il gestore connessioni?

[METODO B]

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

Will connman.shutdown() soffrono problemi di prestazioni?

Posso sapere quale metodo (A o B) è migliore, per l'applicazione utilizzando un thread 50 ++?

risposta

16

Il metodo A è raccomandato dalla comunità di sviluppatori httpclient.

Per ulteriori dettagli, consultare http://www.mail-archive.com/[email protected]/msg02455.html.

+1

Quando si chiama "shutdown" su connection manager se il client è globale. –

+1

Quali strumenti/comandi di linux sono utili per eseguire il debug o "visualizzare" il comportamento di ConnectionManager sotto il cofano? Chiedo perché attualmente abbiamo problemi con le connessioni in CLOSE_WAIT e altri effetti e stiamo cercando di trovare un buon modo per vedere cosa sta succedendo esattamente. – Christoph

+0

@WandMaker Sono abbastanza sicuro che chiamereste shutdown quando il programma termina o quando avete finito con un po 'di lavoro in cui non avrete bisogno di alcuna connessione per un po' di tempo. –

12

mia lettura dei documenti è che HttpConnection per sé non è trattato come thread-safe, e quindi MultiThreadedHttpConnectionManager fornisce un pool riutilizzabile di HttpConnections, si dispone di un unico MultiThreadedHttpConnectionManager condiviso da tutte le discussioni e inizializzato esattamente una volta. Quindi è necessario un paio di piccoli perfezionamenti per l'opzione A.

MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManag 

Poi ogni thread dovrebbe essere utilizzando la sequenza per ogni richiesta, ottenendo in contatto dalla piscina e rimetterlo al termine del suo lavoro - utilizzando un fine il blocco può essere buono. Si dovrebbe inoltre codificare la possibilità che il pool non abbia connessioni disponibili ed elaborare l'eccezione di timeout.

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

Come si utilizza un pool di connessioni non sarà effettivamente essere la chiusura delle connessioni e quindi questo non dovrebbe colpire il problema TIME_WAIT. Questo approccio presuppone che ogni thread non si blocchi alla connessione per molto tempo. Si noti che Conman stesso è rimasto aperto.

+0

Non ha risposto alla mia domanda, su quale metodo (A o B) è migliore. –

+4

La risposta è stata che nessuno dei due è corretto. Lo svelerò. – djna

5

Penso che vorrete usare ThreadSafeClientConnManager.

Si può vedere come funziona qui: http://foo.jasonhudgins.com/2009/08/http-connection-reuse-in-android.html

O nel AndroidHttpClient che usa internamente.

+1

Opps. Nessun piano per la migrazione da HttpClient 3.x alla 4.x, come 3.x era stato in esecuzione impeccabile nella mia applicazione per quasi due anni ~ :) –

+9

Certo, basta se qualcun altro è venuto qui Googling per una risposta :) –

41

Definitivamente Metodo A perché è raggruppato e sicuro per thread.

Se si utilizza httpclient 4.x, il gestore connessioni è chiamato ThreadSafeClientConnManager. Vedere questo link per ulteriori dettagli (scorrere verso il basso fino a "Pooling connection manager"). Per esempio:

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); 
+44

[ThreadSafeClientConnManager ] (http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/conn/tsccm/ThreadSafeClientConnManager.html) è stato deprecato in favore di [PoolingClientConnManager] (http: //hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/conn/PoolingClientConnectionManager.html) in 4.2 –

+0

Ciao, può la httpclient creato da questo metodo essere utilizzato per mantenere la sessione come descritto qui http://stackoverflow.com/questions/5960832/maintaining-session-in-android-application-stay-authenticated-on-the-server-si ...? Perché quando ho provato, non ero in grado di mantenere la sessione fra richieste diffrent ... – sakthig

+11

4.3.1 qui: PoolingClientConnManager è stato deprecato in favore di PoolingHttpClientConnectionManager. – Matthias

0

Con HttpClient 4.5 si può fare questo:

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

Nota che questo implementa Closeable (per lo spegnimento della gestione connessione).