Как выполнить код после асинхронного http-запроса только один раз - PullRequest
0 голосов
/ 11 июня 2018

Я разрабатываю библиотеку, которая вызывает и запрашивает данные с URL-адреса в Интернете, используя метод requestAndParse().Я хочу сделать библиотеку устойчивой к тому, чтобы пользователь несколько раз быстро обращался к серверу.

Асинхронный метод в настоящее время состоит из двух частей.Во-первых, он запрашивает данные из URL, используя request = client.GetStringAsync.Затем он анализирует эти данные из результата request и возвращает эти данные в форме структуры.Для целей этого примера я вызываю эту структуру Data.

. У меня уже есть код, который защищает от нескольких запросов http, сохраняя httprequest в качестве переменной и создавая новый экземпляр только в том случае, если старый запросзавершено или не существует (пусто).

Затем следующая часть анализирует данные.Это очень долгий процесс, который я хотел бы запустить только один раз для каждого httpRequest.Однако, так как мой код настроен прямо сейчас, часть синтаксического анализа будет запускаться каждый раз, когда выполняется код requestAndParse(), даже если есть только один http-запрос.

Код - это нечто вроде строки:

 class ServerRequester {
    private HttpClient = client;
    private Task<string> request = null;

    public async Task<Data> requestAndParse() {
       if (request == null || request.IsCompleted()) {
           // Instantiate new request if there is nothing running already
           request = client.GetStringAsync(url);
        }
        // Wait for request
        this.response = await request;

        /**
         ** 
         ** parse data
         ** ...
         **/
         return data;
    }
}

Дело в том, что если я, например, вызову requestAndParse() 10 раз очень быстро, мне придется анализировать одни и те же данные из одного и того же http-запроса 10 раз.Если синтаксический анализ стоит дорого, или если анализирует состояние магазина для последующего использования, это означает, что я добавлю одни и те же данные 10 раз.Есть ли способ сделать этот код выполненным только один раз, но все же возвращенным в цикл for, просто отлично?

Ответы [ 2 ]

0 голосов
/ 11 июня 2018

Похоже, вы хотите избежать новых запросов, когда запрос уже выполняется.Один из способов управления этим путем использования lock:

class ServerRequester {
    private readonly Object obj = new Object();
    private object Data; // I don't know what is the type of Data

    public async Task<Data> requestAndParse()
    {
        lock (this.obj)
        {
            if (this.Data == null)
            {
                // Wait for request
                this.response = await client.GetStringAsync(url);

                /**
                ** 
                ** parse data
                ** ...
                **/
            }
        }
        return this.Data;
    }
}

Если второй вызов выполняется в том же экземпляре ServerRequester, в то время как первый вызов все еще анализирует или ожидает HTTP-вызов остановится в операторе lock.После снятия блокировки при первом вызове второй вызов (и любые другие последующие вызовы) проверит, отличается ли this.Data от null (что означает, что вы уже проанализировали данные).Если это не так, он просто возвращает кэшированные данные.В противном случае он выполнит http-вызов и выполнит запрос.

Если вы хотите кэшировать данные и заблокировать связанные вызовы независимо от того, какой экземпляр ServerRequester выполняет вызов, установите статический obj.

В качестве примечания: если у вас есть контроль над внутренним API, вы можете также кэшировать данные в API, учитывая, что у вас может быть много клиентов, которые их используют.

0 голосов
/ 11 июня 2018

Вместо того, чтобы хранить Task<string>, который представляет запрос к серверу на необработанные данные, просто кэшируйте Task<Data>, который представляет запрос к серверу на необработанные данные и анализируйте его.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...