从调用方法并行执行方法
我有一个库,客户正在使用它,他们正在传递具有的对象,以及其中的其他一些字段。现在我使用这个对象来创建一个URL,然后我进行HTTP调用,我的服务返回一个JSON响应,我用它来创建一个对象,并将这个对象返回给他们。DataRequest
userid
timeout
DataRequest
RestTemplate
DataResponse
DataResponse
下面是客户通过将对象传递给它来使用的我的类。我正在使用客户传入的超时值来超时请求,如果它在方法上花费了太多时间。DataClient
DataRequest
DataRequest
getSyncData
public class DataClient implements Client {
private RestTemplate restTemplate = new RestTemplate();
// first executor
private ExecutorService service = Executors.newFixedThreadPool(15);
@Override
public DataResponse getSyncData(DataRequest key) {
DataResponse response = null;
Future<DataResponse> responseFuture = null;
try {
responseFuture = getAsyncData(key);
response = responseFuture.get(key.getTimeout(), key.getTimeoutUnit());
} catch (TimeoutException ex) {
response = new DataResponse(DataErrorEnum.CLIENT_TIMEOUT, DataStatusEnum.ERROR);
responseFuture.cancel(true);
// logging exception here
}
return response;
}
@Override
public Future<DataResponse> getAsyncData(DataRequest key) {
DataFetcherTask task = new DataFetcherTask(key, restTemplate);
Future<DataResponse> future = service.submit(task);
return future;
}
}
DataFetcherTask
类:
public class DataFetcherTask implements Callable<DataResponse> {
private DataRequest key;
private RestTemplate restTemplate;
public DataFetcherTask(DataRequest key, RestTemplate restTemplate) {
this.key = key;
this.restTemplate = restTemplate;
}
@Override
public DataResponse call() throws Exception {
// In a nutshell below is what I am doing here.
// 1. Make an url using DataRequest key.
// 2. And then execute the url RestTemplate.
// 3. Make a DataResponse object and return it.
// I am calling this whole logic in call method as LogicA
}
}
截至目前,我的类负责一个键,如上所示。DataFetcherTask
DataRequest
问题陈述:-
现在我有一个小小的设计更改。客户将使用(keyA)对象(例如keyA)对象传递给我的库,然后我将通过使用(keyA)对象中存在的用户ID对另一个服务(我在当前设计中没有这样做)进行新的http调用,这将为我提供用户ID的列表,因此我将使用这些用户ID并进行其他一些(keyB, keyC, keyD) 对象一个,用于响应中返回的每个用户 ID。然后我将有对象,它将具有keyB,keyC和keyD对象。Max 元素中的将有三个,仅此而已。DataRequest
DataRequest
DataRequest
List<DataRequest>
DataRequest
List<DataRequest>
现在,对于其中的每个对象,我想并行执行上述方法,然后通过为每个键添加每个对象来制作。因此,我将对 .此并行调用背后的想法是获取同一全局超时值中最多三个键的数据。DataRequest
List<DataRequest>
DataFetcherTask.call
List<DataResponse>
DataResponse
DataFetcherTask.call
所以我的建议是 - 类将返回对象而不是,然后签名和方法也会改变。所以这是算法:DataFetcherTask
List<DataResponse>
DataResponse
getSyncData
getAsyncData
- 使用客户传递的数据请求对象,通过调用另一个 HTTP 服务来制作。
List<DataRequest>
- 对 方法中的每个 in 进行并行调用,并将对象返回给客户而不是 。
DataRequest
List<DataRequest>
DataFetcherTask.call
List<DataResponse>
DataResponse
通过这种方式,我也可以在步骤1和步骤2上应用相同的全局超时。如果上述任何一步需要时间,我们将只是在方法中超时。getSyncData
DataFetcherTask
设计更改后的类:
public class DataFetcherTask implements Callable<List<DataResponse>> {
private DataRequest key;
private RestTemplate restTemplate;
// second executor here
private ExecutorService executorService = Executors.newFixedThreadPool(10);
public DataFetcherTask(DataRequest key, RestTemplate restTemplate) {
this.key = key;
this.restTemplate = restTemplate;
}
@Override
public List<DataResponse> call() throws Exception {
List<DataRequest> keys = generateKeys();
CompletionService<DataResponse> comp = new ExecutorCompletionService<>(executorService);
int count = 0;
for (final DataRequest key : keys) {
comp.submit(new Callable<DataResponse>() {
@Override
public DataResponse call() throws Exception {
return performDataRequest(key);
}
});
}
List<DataResponse> responseList = new ArrayList<DataResponse>();
while (count-- > 0) {
Future<DataResponse> future = comp.take();
responseList.add(future.get());
}
return responseList;
}
// In this method I am making a HTTP call to another service
// and then I will make List<DataRequest> accordingly.
private List<DataRequest> generateKeys() {
List<DataRequest> keys = new ArrayList<>();
// use key object which is passed in contructor to make HTTP call to another service
// and then make List of DataRequest object and return keys.
return keys;
}
private DataResponse performDataRequest(DataRequest key) {
// This will have all LogicA code here which is shown in my original design.
// everything as it is same..
}
}
现在我的问题是 -
- 它必须像这样吗?解决这个问题的正确设计是什么?我的意思是在另一种方法中有方法看起来很奇怪?
call
call
- 我们是否需要有两个像我在代码中的执行器?有没有更好的方法来解决这个问题,或者我们可以在这里做任何类型的简化/设计更改?
我已经简化了代码,以便这个想法清楚地了解我想要做什么。