问题描述
我需要创建一个具有同步和异步功能的库.
I need to make a library in which I will have synchronous and asynchronous feature.
-
executeSynchronous()
-等待直到得到结果,然后返回结果. -
executeAsynchronous()
-立即返回一个Future,如果需要,可以在完成其他操作之后进行处理.
executeSynchronous()
- waits until I have a result, returns the result.executeAsynchronous()
- returns a Future immediately which can be processed after other things are done, if needed.
我的图书馆的核心逻辑
客户将使用我们的库,他们将通过传递DataKey
构建器对象来调用它.然后,我们将使用该DataKey
对象构造一个URL,并通过执行该URL对该URL进行HTTP客户端调用,然后将响应作为JSON字符串返回给我们,然后将该JSON字符串按原样发送回我们的客户通过创建DataResponse
对象.有些客户会调用executeSynchronous()
,有些客户可能会调用executeAsynchronous()
方法,所以这就是为什么我需要在库中分别提供两个方法.
The customer will use our library and they will call it by passing DataKey
builder object. We will then construct a URL by using that DataKey
object and make a HTTP client call to that URL by executing it and after we get the response back as a JSON String, we will send that JSON String back to our customer as it is by creating DataResponse
object. Some customer will call executeSynchronous()
and some might call executeAsynchronous()
method so that's why I need to provide two method separately in my library.
接口:
public interface Client {
// for synchronous
public DataResponse executeSynchronous(DataKey key);
// for asynchronous
public Future<DataResponse> executeAsynchronous(DataKey key);
}
然后我有实现以上Client
接口的DataClient
:
And then I have my DataClient
which implements the above Client
interface:
public class DataClient implements Client {
private RestTemplate restTemplate = new RestTemplate();
private ExecutorService executor = Executors.newFixedThreadPool(10);
// for synchronous call
@Override
public DataResponse executeSynchronous(DataKey key) {
DataResponse dataResponse = null;
Future<DataResponse> future = null;
try {
future = executeAsynchronous(key);
dataResponse = future.get(key.getTimeout(), TimeUnit.MILLISECONDS);
} catch (TimeoutException ex) {
PotoLogging.logErrors(ex, DataErrorEnum.TIMEOUT_ON_CLIENT, key);
dataResponse = new DataResponse(null, DataErrorEnum.TIMEOUT_ON_CLIENT, DataStatusEnum.ERROR);
} catch (Exception ex) {
PotoLogging.logErrors(ex, DataErrorEnum.CLIENT_ERROR, key);
dataResponse = new DataResponse(null, DataErrorEnum.CLIENT_ERROR, DataStatusEnum.ERROR);
}
return dataResponse;
}
//for asynchronous call
@Override
public Future<DataResponse> executeAsynchronous(DataKey key) {
Future<DataResponse> future = null;
try {
Task task = new Task(key, restTemplate);
future = executor.submit(task);
} catch (Exception ex) {
PotoLogging.logErrors(ex, DataErrorEnum.CLIENT_ERROR, key);
}
return future;
}
}
将执行实际任务的简单类:
Simple class which will perform the actual task:
public class Task implements Callable<DataResponse> {
private DataKey key;
private RestTemplate restTemplate;
public Task(DataKey key, RestTemplate restTemplate) {
this.key = key;
this.restTemplate = restTemplate;
}
@Override
public DataResponse call() {
DataResponse dataResponse = null;
String response = null;
try {
String url = createURL();
response = restTemplate.getForObject(url, String.class);
// it is a successful response
dataResponse = new DataResponse(response, DataErrorEnum.NONE, DataStatusEnum.SUCCESS);
} catch (RestClientException ex) {
PotoLogging.logErrors(ex, DataErrorEnum.SERVER_DOWN, key);
dataResponse = new DataResponse(null, DataErrorEnum.SERVER_DOWN, DataStatusEnum.ERROR);
} catch (Exception ex) {
PotoLogging.logErrors(ex, DataErrorEnum.CLIENT_ERROR, key);
dataResponse = new DataResponse(null, DataErrorEnum.CLIENT_ERROR, DataStatusEnum.ERROR);
}
return dataResponse;
}
// create a URL by using key object
private String createURL() {
String url = somecode;
return url;
}
}
我们公司内的客户将通过在代码库中使用我的工厂来使用我的库,如下所示:
Customer within our company will use my library like this as shown below by using my factory in their code base -
// if they are calling `executeSynchronous()` method
DataResponse response = DataClientFactory.getInstance().executeSynchronous(dataKey);
// and if they want to call `executeAsynchronous()` method
Future<DataResponse> response = DataClientFactory.getInstance().executeAsynchronous(dataKey);
为我的库实现同步和异步方法的最佳方法是什么?实现sync call as async + waiting
是一个坏主意吗?因为使用我的当前设置,每次调用将消耗线程池中的一个线程?如果是,那么任何人都可以解释为什么这是一个坏主意,并且会遇到性能问题吗?
What is the best way to implement sync and async method for my library? Does implementing sync call as async + waiting
is a bad idea? Because it will consume one thread from the thread pool per a call with my currrent setup? If yes, then can anyone explain why it's a bad idea and will it have any performance issue?
根据上述条件,您将如何实现同步和异步方法?做这个的最好方式是什么?该库将在非常重的负载下使用,并且必须快速运行,这意味着无论我的服务器要花多少时间来响应它.
How will you implement sync and async method given the above criteria? What is the best way to do this? This library will be used under very heavy load and it has to be fast, meaning it should take time whatever my server is taking to respond.
我应该在代码库中使用AsyncRestTemplate
这将是异步非阻塞体系结构吗?
Should I use AsyncRestTemplate
in my code base which will be async non-blocking architecture?
推荐答案
如果即使在同步操作的情况下(实际上并不需要)创建新线程,也会导致性能下降.您基本上是在创建新线程(读为浪费资源),甚至没有获得任何好处.话虽这么说,我认为更好的方法是将HTTP部分包装在不同的类中.这样,您将在同步和异步情况下都将代码重新用于HTTP访问.
If you are creating a new thread even in case of synchronous operation(when it is actually not required), it will lead to performance hit. You are basically creating new Thread(read as wasting resources) without even getting any benefits of it.That being said I think better way would be to wrap the HTTP part in a different class. That way you would be re-using the code for HTTP access in both synchronous and asynchronous case.
class HTTPAccess{
private RestTemplate restTemplate;
private DataKey key;
public HTTPAccess(DataKey key,RestTemplate restTemplate){
this.key = key;
this.restTemplate = restTemplate;
}
public DataResponse performRequest() {
DataResponse dataResponse = null;
try {
String url = createURL();
response = restTemplate.getForObject(url, String.class);
// it is a successful response
dataResponse = new DataResponse(response, DataErrorEnum.NONE, DataStatusEnum.SUCCESS);
} catch (RestClientException ex) {
PotoLogging.logErrors(ex, DataErrorEnum.SERVER_DOWN, key);
dataResponse = new DataResponse(null, DataErrorEnum.SERVER_DOWN, DataStatusEnum.ERROR);
} catch (Exception ex) {
PotoLogging.logErrors(ex, DataErrorEnum.CLIENT_ERROR, key);
dataResponse = new DataResponse(null, DataErrorEnum.CLIENT_ERROR, DataStatusEnum.ERROR);
}
return dataResponse;
}
// create a URL by using key object
private String createURL() {
String url = somecode;
return url;
}
}
现在用于Client实现,只需使用此类.
Now for the Client implementation, simply use this class.
public class DataClient implements Client {
private ExecutorService executor = Executors.newFixedThreadPool(10);
private RestTemplate restTemplate;
private void initRestClient(DataKey key){
if(restTemplate == null)
restTemplate = new RestTemplate(clientHttpRequestFactory(key));
}
private ClientHttpRequestFactory clientHttpRequestFactory(DataKey key) {
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setReadTimeout(key.getTimeout());
factory.setConnectTimeout(key.getTimeout());
//if you need to set otherparams this is the place we can do it extracting from DataKey obj
return factory;
}
// for synchronous call
@Override
public DataResponse executeSynchronous(DataKey key) {
initRestClient(key);
DataResponse dataResponse = new HTTPAccess(key).performRequest();
return dataResponse;
}
//for asynchronous call
@Override
public Future<DataResponse> executeAsynchronous(final DataKey key) {
return executor.submit(new Callable<DataResponse>() {
@Override
public DataResponse call() throws Exception {
return executeSynchronous(key);
}
});
}
}
这样,您的HTTP实现是完全独立的,将来,如果您需要更改接收 DataResponse 的方式(可能是通过DB call),则只需更改HTTPAccess类和其他部分不会受到影响.
This way your HTTP implementation is completely separate and in future if you need to change the way to receive DataResponse (maybe from DB call ), then you have to change the HTTPAccess class only and other part will not be affected.
这篇关于在库中实现同步和异步方法的正确方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!