当前位置: 首页 > 知识库问答 >
问题:

在库中实现同步和异步方法的正确方法是什么?

弓玉书
2023-03-14
    null

my Library的核心逻辑

客户将使用我们的库,他们将通过传递DataKeybuilder对象来调用它。然后,我们将通过使用DataKey对象构造一个URL,并通过执行该对象对该URL进行HTTP客户端调用,在将响应作为JSON字符串返回后,我们将通过创建DataResponse对象将该JSON字符串按原样发送给客户。有些客户会调用executeSynchronous(),有些可能会调用executeAsynchronous()方法,所以我需要在库中分别提供两个方法。

接口:

public interface Client {

    // for synchronous
    public DataResponse executeSynchronous(DataKey key);

    // for asynchronous
    public Future<DataResponse> executeAsynchronous(DataKey key);
}
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;
    }
}
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;
    }
}
// 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);

您将如何实现同步和异步方法给定上述标准?做这件事最好的方法是什么?这个库将在非常大的负载下使用,它必须是快速的,这意味着它应该需要时间,无论我的服务器正在采取什么响应。

我是否应该在我的代码库中使用asyncresttemplate(它将是异步非阻塞体系结构)?

共有1个答案

柳刚豪
2023-03-14

如果您正在创建一个新线程,即使在同步操作的情况下(当它实际上不是必需的时候),这将导致性能打击。您基本上是在创建新线程(读作浪费资源),甚至没有从中得到任何好处。话虽如此,我认为更好的方法是将HTTP部分包装在一个不同的类中。这样,您就可以在同步和异步情况下重新使用HTTP访问代码。

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;
    }

}

现在对于客户端实现,只需使用这个类。

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调用),那么您只需要更改HTTPAccess类,其他部分不会受到影响。

 类似资料:
  • 那么,回到问题上来,鉴于微软建议不要在新的开发中使用WebRequest而是使用只提供异步API的HttpClient,我该怎么办呢? 这是我正在做的一些伪代码... 如何实现ProcessStuff()?

  • 问题内容: 我不确定这是否是同步我的的正确方法。 我有一个 从函数传递过来的。 现在,我正在尝试使其同步。这是否正确同步了我的对象? 问题答案: 您要进行两次同步,这是没有意义的,可能会减慢代码的速度:在列表上进行迭代时所做的更改需要整个操作的同步,在这种情况下,使用Using 这样做是多余的(它创建了一个包装程序来同步各个操作)。 但是,由于您要完全清空列表,因此迭代删除第一个元素是最糟糕的方法

  • 本文向大家介绍不同js异步函数同步的实现方法,包括了不同js异步函数同步的实现方法的使用技巧和注意事项,需要的朋友参考一下 不同函数达到同步的函数模拟 funcList是函数执行函数的队列,其中回调函数中flag=true是同步标记量 以上这篇不同js异步函数同步的实现方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持呐喊教程。

  • 问题内容: 当每个呼叫都取决于之前的呼叫是否已完成时,我试图找到创建异步呼叫的最佳方法。目前,我通过递归调用定义的流程函数来链接方法,如下所示。 这就是我目前正在做的。 然后我将其称为如下 虽然这对我来说非常好,但我不禁认为必须有一种更好(更简单)的方法。以后我的递归调用变得太深时,会发生什么? 注意 :我不是在浏览器中使用javascript,而是在Titanium框架中使用本机,这类似于Nod

  • 我正试图从同步方法运行异步方法。但是我不能等待异步方法,因为我在同步方法中。我一定不理解TPL,因为这是我第一次使用它。 每个方法都需要前一个方法来完成,因为第一个方法的数据用于第二个方法。 Await运算符只能在异步方法中使用。考虑用'async'修饰符标记此方法,并将其返回类型更改为'task' 但是,如果我使用async修饰符,这将是一个异步操作。因此,如果我对的调用没有使用await运算符

  • 问题内容: 我正在为MongoDB使用Node.JS驱动程序,我想执行一个同步查询,例如: 问题是,db.open是一个异步调用(它不会阻塞),因此getAThing返回“ undefined”,我希望它返回查询结果。我确定我可以使用某种阻止机制,但我想知道执行此类操作的正确方法。 问题答案: 没有办法使这种同步变得不可怕。正确的方法是接受回调函数作为参数,然后在可用时调用该函数。 节点7.6+更