我正在开发一个基于REST服务的项目,其中我有两个组件,如下所述 -
URL's
的客户URL's
从数据库中获取数据。一般来说,URL看起来像这样 -
http://host.qa.ebay.com:8080/deservice/DEService/get/USERID=9012/PROFILE.ACCOUNT,PROFILE.ADVERTISING,PROFILE.DEMOGRAPHIC,PROFILE.FINANCIAL
上述网址的含义是 - USERID- 9012
为我提供数据库中这些列的数据 -
[PROFILE.ACCOUNT, PROFILE.ADVERTISING, PROFILE.DEMOGRAPHIC, PROFILE.FINANCIAL]
目前我在客户端组件方面进行基准测试。我发现下面的方法正在time(95 Percentile)
周围带来~15ms
一堆。
下面的方法将接受两个参数 -
List<DEKey> keys- sample data in keys will have USERID=9012
List<String> reqAttrNames- sample data for reqAttrNames will be-
[PROFILE.ACCOUNT, PROFILE.ADVERTISING, PROFILE.DEMOGRAPHIC, PROFILE.FINANCIAL]
以下是代码 -
public DEResponse getDEAttributes(List<DEKey> keys, List<String> reqAttrNames) {
DEResponse response = null;
try {
String url = buildGetUrl(keys,reqAttrNames);
if(url!=null){
List<CallableTask<DEResponse>> tasks = new ArrayList<CallableTask<DEResponse>>();
CallableTask<DEResponse> task = new DEResponseTask(url);
tasks.add(task);
// STEP 2: Execute worker threads for all the generated urls
List<LoggingFuture<DEResponse>> futures = null;
try {
long waitTimeout = getWaitTimeout(keys);
futures = executor.executeAll(tasks, null, waitTimeout, TimeUnit.MILLISECONDS);
// STEP 3: Consolidate results of the executed worker threads
if(futures!=null && futures.size()>0){
LoggingFuture<DEResponse> future = futures.get(0);
response = future.get();
}
} catch (InterruptedException e1) {
logger.log(LogLevel.ERROR,"Transport:getDEAttributes Request timed-out :",e1);
}
}else{
//
}
} catch(Throwable th) {
}
return response;
}
上面的方法会让我回到DEResponse
对象。
以下是DEResponseTask class
public class DEResponseTask extends BaseNamedTask implements CallableTask<DEResponse> {
private final ObjectMapper m_mapper = new ObjectMapper();
@Override
public DEResponse call() throws Exception {
URL url = null;
DEResponse DEResponse = null;
try {
if(buildUrl!=null){
url = new URL(buildUrl);
DEResponse = m_mapper.readValue(url, DEResponse.class);
}else{
logger.log(LogLevel.ERROR, "DEResponseTask:call is null ");
}
} catch (MalformedURLException e) {
}catch (Throwable th) {
}finally{
}
return DEResponse;
}
}
这个多线程代码的编写方式有问题吗?如果是的话,我怎样才能提高效率呢?
executeAll
executor
方法的签名,因为在我的公司,他们有自己的执行者,将执行Sun Executor类 -
/**
* Executes the given tasks, returning a list of futures holding their
* status and results when all complete or the timeout expires, whichever
* happens first. <tt>Future.isDone()</tt> is <tt>true</tt> for each
* element of the returned list. Upon return, tasks that have not completed
* are cancelled. Note that a <i>completed</i> task could have terminated
* either normally or by throwing an exception. The results of this method
* are undefined if the given collection is modified while this operation is
* in progress. This is entirely analogous to
* <tt>ExecutorService.invokeAll()</tt> except for a couple of important
* differences. First, it cancels but does not <b>interrupt</b> any
* unfinished tasks, unlike <tt>ExecutorService.invokeAll()</tt> which
* cancels and interrupts unfinished tasks. This results in a better
* adherence to the specified timeout value, as interrupting threads may
* have unexpected delays depending on the nature of the tasks. Also, all
* eBay-specific features apply when the tasks are submitted with this
* method.
*
* @param tasks the collection of tasks
* @param timeout the maximum time to wait
* @param unit the time unit of the timeout argument
* @return a list of futures representing the tasks, in the same sequential
* order as produced by the iterator for the given task list. If the
* operation did not time out, each task will have completed. If it did
* time out, some of these tasks will not have completed.
* @throws InterruptedException if interrupted while waiting, in which case
* unfinished tasks are cancelled
*/
public <V> List<LoggingFuture<V>> executeAll(Collection<? extends CallableTask<V>> tasks,
Options options,
long timeout, TimeUnit unit)
throws InterruptedException {
return executeAll(tasks, options, timeout, unit, false);
}
更新: -
这个组件一旦我增加程序的负载就会花费时间,通过将线程增加到20
进行基准测试
newFixedThreadPool(20)
但我相信如果我使用 -
,这个组件可以正常工作 newSingleThreadExecutor
我能想到的唯一原因可能是上面的代码,有一个阻塞调用,这就是线程被阻塞的原因,这就是为什么需要时间?
更新: -
所以这一行应该这样写? -
if(futures!=null && futures.size()>0){
LoggingFuture<DEResponse> future = futures.get(0);
//response = future.get();//replace this with below code-
while(!future.isDone()) {
Thread.sleep(500);
}
response = future.get();
}
答案 0 :(得分:0)
除了使用复杂的非标准Executor之外,我没有看到任何导致性能损失的内容。我意识到你在使用Executor的问题上没有任何选择,但出于好奇,我会尝试用ThreadPoolExecutor
替换它,看看这是否有所不同,并提出来如果你注意到一个重大改进,你工作的权力 - 在我的工作中我们发现由另一个部门编写的加密库是绝对的废话(我们的CPU时间的80-90%用于他们的代码)并成功游说他们重写它。
编辑:
public class Aggregator implements Runnable {
private static ConcurrentLinkedQueue<Future<DEResponse>> queue = new ConcurrentLinkedQueue<>();
private static ArrayList<DEResponse> aggregation = new ArrayList<>();
public static void offer(Future<DEResponse> future) {
queue.offer(future);
}
public static ArrayList<DEResponse> getAggregation() {
return aggregation;
}
public void run() {
while(!queue.isEmpty()) { // make sure that all of the futures are added before this loop starts; better still, if you know how many worker threads there are then keep a count of how many futures are in your aggregator and quit this loop when aggregator.size() == [expected number of futures]
aggregation.add(queue.poll().get());
}
}
}
public void getDEAttributes(List<DEKey> keys, List<String> reqAttrNames) {
try {
if(url!=null){
try {
futures = executor.executeAll(tasks, null, waitTimeout, TimeUnit.MILLISECONDS);
if(futures!=null && futures.size()>0){
Aggregator.offer(futures.get(0));
}
}
}
}
}
答案 1 :(得分:0)
如果我正确阅读了您的代码,则存在一个明显的性能问题。这样:
public class DEResponseTask extends BaseNamedTask implements CallableTask<DEResponse> {
private final ObjectMapper m_mapper = new ObjectMapper();
每个任务调用一次,ObjectMapper
实例的创建非常昂贵。
有很多方法可以解决这个问题,但您可能想要:
ObjectMapper
(分享是安全的)这样做会对JSON处理效率产生重大影响。