【发布时间】:2014-01-20 18:02:28
【问题描述】:
我不是多线程专家,但我发现当前使用 ExecutorService 的代码存在一些性能问题。
我正在处理一个项目,在该项目中我需要对我的服务器进行 HTTP URL 调用,如果响应时间过长,则调用超时。目前它正在返回简单的 JSON 字符串..
我目前的要求是10 ms。在10 ms 内,它应该能够从服务器取回数据。我想这是可能的,因为它只是对同一数据中心内服务器的 HTTP 调用。
我的客户端程序和实际服务器在同一个数据中心内,并且它们之间的 ping 时间延迟为0.5 ms,所以它应该是可行的..
我使用RestTemplate 来进行 URL 调用。
下面是我为我编写的代码,它使用ExecutorService 和Callables -
public class URLTest {
private ExecutorService executor = Executors.newFixedThreadPool(10);
public String getData() {
Future<String> future = executor.submit(new Task());
String response = null;
try {
System.out.println("Started..");
response = future.get(100, TimeUnit.MILLISECONDS);
System.out.println("Finished!");
} catch (TimeoutException e) {
System.out.println("Terminated!");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return response;
}
}
下面是我的任务类,它实现了Callable 接口 -
class Task implements Callable<String> {
private RestTemplate restTemplate = new RestTemplate();
public String call() throws Exception {
// TimerTest timer = TimerTest.getInstance(); // line 3
String response = restTemplate.getForObject(url, String.class);
// timer.getDuration(); // line 4
return response;
}
}
下面是我在另一个类DemoTest 中的代码,它调用URLTest 类500 times 中的getData 方法,并端到端测量它的第95 个百分位 -
public class DemoTest {
public static void main(String[] args) {
URLTest bc = new URLTest();
// little bit warmup
for (int i = 0; i <= 500; i++) {
bc.getData();
}
for (int i = 0; i <= 500; i++) {
TimerTest timer = TimerTest.getInstance(); // line 1
bc.getData();
timer.getDuration(); // line 2
}
// this method prints out the 95th percentile
logPercentileInfo();
}
}
使用上面的代码,我总是将第 95 个百分位视为14-15 ms(这对我的用例不利,因为它是端到端流,这就是我需要衡量的)。
我很惊讶为什么? ExectuorFramework 是否在这里添加了所有延迟?可能是每个任务都提交了,提交线程一直在等待(通过future.get)直到任务完成..
我的主要目标是尽可能减少这里的延迟。我的用例很简单,在启用 TIMEOUT 功能的情况下对我的一台服务器进行 URL 调用,这意味着如果服务器需要大量时间来响应,然后超时整个通话。客户将从那里调用我们的代码,该应用程序也可以是多线程的..
有什么我遗漏的东西或我需要使用的ExecutorService 的其他风格吗?我怎样才能在这里提高我的表现?任何建议都会有很大帮助..
任何示例都将不胜感激。我正在阅读有关ExecutorCompletionService 的信息,不确定是否应该使用这个或其他东西..
【问题讨论】:
-
真的不明白您希望通过摆弄线程池实现来实现 Web 服务器性能吗?看看网络服务器和网络客户端......!您需要在 Web 客户端上设置超时,以便它真正放弃。随着未来的超时,你只是放弃了任务,但工作线程仍然坐在那里试图做它直到它完成。
-
这对我来说看起来很单线程......
-
这里不是执行器框架的问题。有些事情花费的时间比你预期的要长。我建议考虑运行 Java 分析器。您还可以记录系统各个部分的挂钟毫秒数,以查看花费了这么长时间。
-
此外,即使您的作业超时,它也会继续在后台执行并占用系统资源。杀死 RPC 很重要。
-
@pamphlet:我的用例需要有同步和异步方法,一个用于阻止调用..另一个用于发送未来..根据这些方法,客户端可以调用任何方法他们喜欢..所以这就是我有这个的原因..
标签: java multithreading performance executorservice resttemplate