2015-08-31 3 views
1

Я пытаюсь понять async/await, и мне интересно, работают ли оба метода одинаково. Если вы не можете объяснить, почему?async/await function сравнения

 public async Task<Client> GetClient() 
     { 
      return await _clientRepository.GetAll().Where(x => x.Id == 1).FirstOrDefaultAsync(); 
     } 

     public Task<Client> GetClient2() 
     { 
      return Task.FromResult(_clientRepository.GetAll().Where(x => x.Id == 1).FirstOrDefault()); 
     } 

public async Task Run() 
{ 
     var result = await GetClient(); 
     var result2 = await GetClient2(); 
} 
+0

Я рекомендую прочитать эту статью [] (http://davidwalsh.name/async-generators), это объясняет асинхронный/Await от точки генератора/обещания зрения. – MinusFour

+1

Они совершенно разные и даже вызывают разные методы внутри ... Как вы ожидаете, что эти два метода будут одинаковыми? –

+0

Делает _clientRepository.GetAll(). Где (x => x.Id == 1) .FirstOrDefaultAsync(); равно Task.FromResult (_clientRepository.GetAll(). Где (x => x.Id == 1) .FirstOrDefault()); – user1075940

ответ

1

Позвольте мне указать несколько вещей, с функциями:

public async Task<Client> GetClient() 
{ 
    return await _clientRepository.GetAll().Where(x => x.Id == 1).FirstOrDefaultAsync(); 
} 

Это первая функция немного расточительно. Ни async, ни await не дают вам никакой пользы. Почему я так говорю? Хорошо, давайте просто быстро рассмотрим обычное преимущество await.

Что может сделать await - это возобновление выполнения остатка метода после завершения ожидаемой задачи. В вашем случае нет «остатка метода», поскольку return await является последней инструкцией метода.

Почему это расточительно? Ну, помечая свой метод async, вы в основном говорите компилятору, чтобы сгенерировать все оборудование (то есть конечный автомат), чтобы вы могли возобновить выполнение внутри этого же метода после каждого ожидания.

Эта техника бесполезна в вашем случае, так как нет ничего после AWAIT возобновить выполнение, так что вы лучше не маркировки метода async и вместо return await просто сделать простой возврат задачи, порожденной FirstOrDefaultAsync.

Выполнение этого будет по-прежнему возвращать функцию и вести себя асинхронно. Имейте в виду, что async и await на самом деле не выполняют функцию асинхронно.async/await просто помогают настроить механизм для обеспечения «закладок» в различные точки ожидания вашего метода, чтобы выполнение могло возобновиться там после завершения каждой ожидаемой задачи.

Теперь давайте поговорим о вашей второй функции:

public Task<Client> GetClient2() 
    { 
    return Task.FromResult(_clientRepository.GetAll().Where(x => x.Id == 1).FirstOrDefault()); 
    } 

Эта функция не асинхронной вообще. Он выполнит полностью синхронный и не даст нить вообще.

Даже если вы сделали это:

public async Task<Client> GetClient2() 
    { 
    return await Task.FromResult(_clientRepository.GetAll().Where(x => x.Id == 1).FirstOrDefault()); 
    } 

Функция по-прежнему будет полностью синхронным. Помните, что async/await - все о настройке машин и закладок, но на самом деле не играют никакой роли в том, будет ли код выполняться синхронно или асинхронно.

Так почему же это блокирование? Поскольку FirstOrDefault() не возвращает задачу, значит, она должна вернуть объект Client. Это означает, что он не может вернуть ничего, пока он полностью не завершит выполнение цепочки linq. Затем ваш Task.FromResult просто принимает это значение и завершает его в предварительно выполненной задаче.

Так просто резюмировать:

использовать только async/await если вам нужно возобновить выполнение где-то в середине вашего метода.

Пример:

public async Task<boolean> IsIntegerIGetFromRemoteServerPostitiveAsync(){ 
     int result = await GetSomeIntegerAsync(); 
     Console.WriteLine('Resuming execution of the method'); 
     return i>0; 
} 

Если вы обнаружите, что у вас есть один ОЖИДАНИЕ и это последняя строка метода не используйте async/await, просто вернуть задание вместо ожидании его. Это позволяет избежать лишних накладных расходов.

Пример:

public Task<string> GetUserInformationAsync(string username){ 
    var url = $"http://userinfo.com?username={username}" 
    return GetSomeJsonFromHttpServerAsync(url); //Assuming this returns Task<string> 
} 
2

Это не то же самое, когда вы добавляете ключевое слово async, вы включаете следующие две возможности.

  • Маркированный метод асинхронного использования может использовать Await или ждать, чтобы обозначить точки подвески. Оператор ожидания сообщает компилятору, что метод async не может продолжить эту точку до тех пор, пока ожидаемый асинхронный процесс не будет завершен. Тем временем, управление возвращается к вызывающей стороне метода async.

    Подвеска асинхронного метода при выражении ожидания не является выходом из метода, и, наконец, блоки не запускаются.

  • Отмеченный метод async можно ожидать от методов, которые его называют.

Вы должны прочитать асинхронной/ОЖИДАНИЕ документацию здесь: https://msdn.microsoft.com/en-us/library/hh191443.aspx

+3

«вы не сможете ждать функции, которая не является асинхронной». - это * несколько * неправильно ... Я имею в виду, если метод возвращает 'Task', вы всегда можете его ожидать, независимо от того, содержит ли метод' async' или нет, но таких случаев тоже есть. Дополнительная информация http://blog.stephencleary.com/2012/02/async-and-await.html –

1

Первый метод: асинхронной ключевое слово дает сигнал компилятор для генерации состояния машины. Событие, если у вас есть пустой метод void, помеченный как async, компилятор будет генерировать конечный автомат.

Второй способ: Вы возвращаете «горячую задачу» - задание, которое уже завершено. Этот метод будет действовать как обычный метод.

Кстати, это хорошая идея для второго сценария кэшировать такие задачи. Например, вы можете создавать словарные слова и возвращать кешированную задачу. Если вы это сделаете, вы не будете выделять каждый раз новую задачу в кучу.

Смежные вопросы