2009-08-15 10 views
78

Durante un tiempo, he estado usando HttpClient en un entorno multiproceso. Para cada hilo, cuando inicia una conexión, creará una instancia HttpClient completamente nueva.Mejores prácticas para usar HttpClient en entornos multiproceso

Recientemente, he descubierto que, al usar este enfoque, puede causar que el usuario tenga demasiados puertos abiertos y la mayoría de las conexiones están en el estado TIME_WAIT.

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

Por lo tanto, en lugar de cada hilo haciendo:

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

Planeamos tener:

[MÉTODO A]

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

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

En una situación normal, global_c será accedido por 50 ++ hilos al mismo tiempo. Me preguntaba, ¿creará esto algún problema de rendimiento? ¿MultiThreadedHttpConnectionManager utiliza un mecanismo sin bloqueo para implementar su política de seguridad de subprocesos?

Si 10 hilos están usando global_c, ¿se bloquearán los otros 40 hilos?

¿O sería mejor si, en cada hilo, creo una instancia de un HttpClient, pero lanzo el administrador de conexión explícitamente?

[procedimiento B]

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

Will connman.shutdown() sufren problemas de rendimiento?

¿Se puede saber qué método (A o B) es mejor, para la aplicación que utiliza un 50 ++ hilos?

Respuesta

16

El método A es recomendado por la comunidad de desarrolladores de httpclient.

Consulte http://www.mail-archive.com/[email protected]/msg02455.html para obtener más información.

+1

¿Cuándo se llamará "shutdown" al administrador de conexión si el cliente se globaliza? –

+1

¿Qué herramientas/comandos de Linux son útiles para depurar o "visualizar" el comportamiento del ConnectionManager bajo el capó? Pregunto porque actualmente tenemos problemas con las conexiones en CLOSE_WAIT y otros efectos, y nos estamos esforzando por encontrar una buena manera de ver qué está sucediendo exactamente. – Christoph

+0

@WandMaker Estoy bastante seguro de que simplemente llamaría al apagado cuando salga el programa o cuando haya terminado con un lote de trabajo en el que no necesitará ninguna conexión durante un tiempo. –

12

Mi lectura de los documentos es que HttpConnection sí mismo no es tratado como hilo de seguridad, y por lo tanto proporciona una piscina MultiThreadedHttpConnectionManager reutilizable de HttpConnections, que tiene un único MultiThreadedHttpConnectionManager compartida por todas las discusiones y inicializado exactamente una vez. Así que hay un par de pequeñas mejoras a la opción A.

MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManag 

A continuación, cada hilo debe estar utilizando la secuencia para cada solicitud, para conseguir una conexión desde la piscina y volver a colocarlo en la terminación de su trabajo - con un fin bloque puede ser bueno. También debe codificar la posibilidad de que el grupo no tenga conexiones disponibles y procesar la excepción de tiempo de espera.

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

Como está utilizando un conjunto de conexiones que no se realiza ningún cerrando las conexiones y por lo tanto esto no debe golpear el problema TIME_WAIT. Este enfoque supone que cada hilo no se queda en la conexión por mucho tiempo. Tenga en cuenta que el estafador se deja abierto.

+0

No respondí realmente a mi pregunta, en qué método (A o B) es mejor. –

+4

La respuesta fue que ninguno de los dos es correcto. Lo deletrearé. – djna

5

Creo que querrá utilizar ThreadSafeClientConnManager.

Puede ver cómo funciona aquí: http://foo.jasonhudgins.com/2009/08/http-connection-reuse-in-android.html

O en el AndroidHttpClient que utiliza internamente.

+1

Opps. Ningún plan para migrar de HttpClient 3.x a 4.x, ya que 3.x ha estado funcionando impecablemente en mi aplicación durante casi ~ 2 años :) –

+9

Claro, solo si alguien más vino aquí buscando una respuesta :) –

41

Definitivamente Método A porque está agrupado y es seguro para hilos.

Si está utilizando httpclient 4.x, el administrador de conexión se llama ThreadSafeClientConnManager. Consulte esto link para obtener más detalles (desplácese hacia abajo para "Pooling connection manager"). Por ejemplo:

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) ha quedado en desuso en favor de [PoolingClientConnManager] (http: //hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/conn/PoolingClientConnectionManager.html) en 4.2 –

+0

Hola, ¿se puede usar el httpclient creado con este método para mantener la sesión como descrito aquí http://stackoverflow.com/questions/5960832/maintaining-session-in-android-application-stay-authenticated-on-the-server-si ...? Porque cuando lo intenté, no pude mantener la sesión en diferentes solicitudes ... – sakthig

+11

4.3.1 aquí: PoolingClientConnManager ha quedado en desuso en favor de PoolingHttpClientConnectionManager. – Matthias

0

Con HttpClient 4.5 se puede hacer esto:

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

Tenga en cuenta que éste implementa se puede cerrar (para el cierre del administrador de conexión).

Cuestiones relacionadas