如何在Java中执行非阻塞HTTP调用?

8
我有一个第三方API,我使用HTTP GET请求来调用它。每个请求需要几秒钟才能得到响应。
目前我正在使用CompletableFuture,在大小为64的FixedThreadPool上执行。这会导致线程被阻塞,直到收到GET请求的响应,也就是说,线程在发送GET响应后一直处于空闲状态,直到接收到响应。因此,我可以发送的最大同时请求数受到线程大小的限制,即这里的64。
有什么替代CompletableFuture的方法,使得我的线程不会空闲等待响应?

那就增加线程池的大小,或者使用无限制的线程池。但是你真的有同时存在64个待处理的GET请求吗? - user207421
1
我实际上可以同时拥有数千个GET请求。除了使用一个这样大小的线程池之外,还有其他方法吗?这些线程只需要发送GET请求并收集响应。 - Aayush Dwivedi
有数千个空闲线程并没有什么问题,而非阻塞式HTTP的实现非常困难。 - user207421
所以将它设置得更低一些。无论如何,您实际上也不能同时执行数千个GET请求。网络不是多线程的。但是你引用的问题已经八年了。您需要进行一些实验。 - user207421
@Oleg,就像我说的那样,把它缩小。将其缩小到核心数量,并使它们等效。 - user207421
显示剩余4条评论
1个回答

8
正如@user207421所言:
- 一个真正异步(即事件驱动)的HTTP客户端应用程序很复杂。 - 基于多线程(但基本上是同步的)的HTTP客户端应用程序更简单,并且可以扩展到您拥有足够内存的线程数。 - 假设您有64个工作线程正在处理请求,实际瓶颈可能是物理网络带宽或客户端可用CPU。如果已达到这些限制,则: - 增加工作线程的数量不会有所帮助,并且 - 切换到异步(事件驱动)模型也不会有所帮助。 - 第三种可能性是瓶颈是服务器端资源限制或速率限制。在这种情况下,增加客户端线程计数可能有所帮助,不会产生影响或使问题变得更糟。这将取决于服务器的实现方式、请求的性质等。 如果您的瓶颈确实是线程数,那么要尝试的一个简单方法是减少工作线程堆栈大小,以便您可以运行更多的线程。默认堆栈大小通常为1MB,这可能比实际需要的要大得多。(如果这是一个真正的问题,这也将减少空闲线程的内存开销。) Java有一些异步HTTP客户端库。但我从未使用过,也不能推荐任何一个。象@user207421一样,我也不确定改变的努力实际上是否会有回报。
“我该怎么做才能让我的线程不闲置等待响应呢?”
空闲线程实际上不是问题。空闲线程只使用内存(和一些可能并不重要的次要效果)。除非您的内存不足,否则它几乎没有什么影响。
注意:如果在服务器响应等待期间,客户端还有其他事情要做,操作系统线程调度程序将切换到另一个线程。
“因此,我可以发送的最大并发请求数受到我的线程池大小限制,即这里是64。”
是的,这是真的。但是,发送更多的并发请求可能不会有所帮助。如果客户端线程处于空闲状态,那么这很可能意味着瓶颈要么是网络,要么是服务器端的“某些东西”。如果是这种情况,增加线程数不会增加吞吐量。相反,单个请求将需要(平均而言)更长的时间,吞吐量将保持不变...或者可能会降低,如果服务器开始从其请求队列中丢弃请求的话。
最后,如果您担心大量空闲工作线程的开销(等待下一个任务),请使用可以缩小和增长其线程池以满足不断变化的工作负载的执行服务或连接池。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接