在多线程环境中使用 HttpClient 的最佳实践

发布于 2024-08-02 03:40:52 字数 1526 浏览 4 评论 0原文

一段时间以来,我一直在多线程环境中使用 HttpClient。 对于每个线程,当它发起连接时,都会创建一个全新的 HttpClient 实例。

最近我发现,使用这种方法会导致用户打开的端口过多,并且大部分连接处于TIME_WAIT状态。

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

因此,而不是每个线程执行:

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

我们计划:

[方法 A]

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

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

正常情况下,global_c将被50++个线程同时访问。 我想知道,这会产生任何性能问题吗? MultiThreadedHttpConnectionManager是否使用无锁机制来实现其线程安全策略?

如果有10个线程使用global_c,其他40个线程会被锁定吗?

或者,如果在每个线程中创建 HttpClient 的实例,但显式释放连接管理器,会更好吗?

[方法 B]

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

connman.shutdown() 会遇到性能问题吗?

我可以知道对于使用 50++ 线程的应用程序,哪种方法(A 或 B)更好?

For a while, I have been using HttpClient in a multithreaded environment. For every thread, when it initiates a connection, it will create a completely new HttpClient instance.

Recently, I have discovered that, by using this approach, it can cause the user to have too many ports being opened, and most of the connections are in TIME_WAIT state.

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

Hence, instead of each thread doing :

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

We plan to have :

[METHOD A]

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

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

In a normal situation, global_c will be accessed by 50++ threads concurrently. I was wondering, will this create any performance issues? Is MultiThreadedHttpConnectionManager using a lock-free mechanism to implement its thread safe policy?

If 10 threads are using global_c, will the other 40 threads be locked?

Or would it be better if, in every thread, I create an instance of an HttpClient, but release the connection manager explicitly?

[METHOD B]

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

Will connman.shutdown() suffer performance issues?

May I know which method (A or B) is better, for application using an 50++ threads?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

冷弦 2024-08-09 03:40:52

肯定是方法 A,因为它是池化且线程安全的。

如果您使用的是httpclient 4.x,则连接管理器称为ThreadSafeClientConnManager。 请参阅此链接了解更多详细信息(向下滚动到“池连接管理器”)。 例如:

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

Definitely Method A because its pooled and thread safe.

If you are using httpclient 4.x, the connection manager is called ThreadSafeClientConnManager. See this link for further details (scroll down to "Pooling connection manager"). For example:

    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);
要走干脆点 2024-08-09 03:40:52

方法A是httpclient开发者社区推荐的。

请参考 http://www.mail-archive.com /[电子邮件受保护]/msg02455.html 了解更多详细信息。

Method A is recommended by httpclient developer community.

Please refer http://www.mail-archive.com/[email protected]/msg02455.html for more details.

还在原地等你 2024-08-09 03:40:52

我对文档的阅读是,HttpConnection 本身不被视为线程安全,因此 MultiThreadedHttpConnectionManager 提供了一个可重用的 HttpConnection 池,您有一个由所有线程共享的 MultiThreadedHttpConnectionManager 并只初始化一次。 因此,您需要对选项 A 进行一些小的改进。

MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManag

然后每个线程应该对每个请求使用该序列,从池中获取一个连接并在完成其工作后将其放回原处 - 使用finally 块可能会很好。
您还应该针对池没有可用连接的可能性进行编码并处理超时异常。

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

当您使用连接池时,您实际上不会关闭连接,因此这不应该遇到 TIME_WAIT 问题。 这种方法确实假设每个线程不会长时间挂起连接。 请注意,conman 本身保持打开状态。

My reading of the docs is that HttpConnection itself is not treated as thread safe, and hence MultiThreadedHttpConnectionManager provides a reusable pool of HttpConnections, you have a single MultiThreadedHttpConnectionManager shared by all threads and initialised exactly once. So you need a couple of small refinements to option A.

MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManag

Then each thread should be using the sequence for every request, getting a conection from the pool and putting it back on completion of its work - using a finally block may be good.
You should also code for the possibility that the pool has no available connections and process the timeout exception.

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

As you are using a pool of connections you won't actually be closing the connections and so this should not hit the TIME_WAIT problem. This approach does assuume that each thread doesn't hang on to the connection for long. Note that conman itself is left open.

离线来电— 2024-08-09 03:40:52

使用 HttpClient 4.5,您可以执行以下操作:

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

请注意,这个实现了 Closeable(用于关闭连接管理器)。

With HttpClient 4.5 you can do this:

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

Note that this one implements Closeable (for shutting down of the connection manager).

迷鸟归林 2024-08-09 03:40:52

我想你会想使用 ThreadSafeClientConnManager。

您可以在这里查看它的工作原理: http:// foo.jasonhudgins.com/2009/08/http-connection-reuse-in-android.html

或者在内部使用它的 AndroidHttpClient 中。

I think you will want to use ThreadSafeClientConnManager.

You can see how it works here: http://foo.jasonhudgins.com/2009/08/http-connection-reuse-in-android.html

Or in the AndroidHttpClient which uses it internally.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文