В чем разница между использованием .Result внутри тела задачи и использованием await в асинхронном методе? - PullRequest
0 голосов
/ 06 октября 2018

Мне удалось найти ответы на похожие вопросы, размещенные в Интернете, но никто из них не объяснил, что это достаточно удовлетворительно, чтобы я смог понять разницу в приведенном ниже коде.

Я знаю, что жду, в отличие от.Результат, не блокирует вызывающий поток.Но что, если мы пытаемся получить доступ к этому свойству из задачи, которая не блокирует его в любом случае?

Например, есть ли разница между этим

public static Task PrintPageAsync(string url)
{
    return Task.Run(() =>
    {
        WebRequest webRequest = WebRequest.Create(url);
        WebResponse response = webRequest.GetResponseAsync().Result;
        using (StreamReader reader = new StreamReader(response.GetResponseStream()))
        {
            string text = reader.ReadToEndAsync().Result;
            Console.WriteLine(text);
        }
    });
}

и этим

public static async Task PrintPageAsync(string url)
{
    WebRequest webRequest = WebRequest.Create(url);
    WebResponse response = await webRequest.GetResponseAsync();
    using (StreamReader reader = new StreamReader(response.GetResponseStream()))
    {
        string text = await reader.ReadToEndAsync();
        Console.WriteLine(text);
    }
}

Ответы [ 2 ]

0 голосов
/ 06 октября 2018

Так как первый пример запускает новую задачу в потоке потоков, вызов асинхронных методов не требуется, когда существуют эквивалентные синхронные методы.Это не дает никаких преимуществ, просто добавляет ненужные накладные расходы на управление асинхронными задачами.Просто используйте .GetResponse() вместо .GetResponseAsync().Result и .ReadToEnd() вместо .ReadToEndAsync().Result.

await, в отличие от .Result, не блокирует вызывающий поток

Это не всегда верно.Ожидаемые методы могут выполняться (частично или полностью) синхронно, если они решат это сделать.

Например, есть ли разница?

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

  1. AggregateException

    Когда в задаче возникает исключение илиотменено, вызов Task.Result обернет исключение в AggregateException.Напротив, await при выполнении этого задания будет получено исходное исключение.Поэтому вы должны быть осторожны при catch конкретном исключении.

  2. Thread

    В первом примере весь метод будет выполняться на одном и том же(Threadpool) поток.Второй пример может выполняться в нескольких разных потоках, в зависимости от текущего SynchronizationContext.Код, чувствительный к thread-affinity , следует избегать.

  3. SynchronizationContext

    Первый пример будет выполнен без SynchronizationContext,в то время как второй восстановит исходный SynchronizationContext после каждого await.Для консольных приложений это не имеет значения.Но в приложениях WPF или WinForms элементы пользовательского интерфейса могут быть доступны только из соответствующего контекста синхронизации.

  4. Асинхронное выполнение

    В первом примере PrintPageAsync вернется сразу после того, как новое задание будет поставлено в очередь на выполнение, а второе будет выполняться синхронно до первого await (или, возможно, даже после этого).Это может оказать серьезное влияние на отклики GUI, особенно когда асинхронный метод использует WebRequest, потому что метод GetResponseAsync() выполняет разрешение DNS синхронно (см. Как создать HttpWebRequest без прерывания async / await? ).Поэтому рекомендуется переносить код в Task.Run(), когда метод, использующий WebRequest, вызывается из потока пользовательского интерфейса.

0 голосов
/ 06 октября 2018

.Result выполнит ваш код синхронно, т.е. вы игнорируете саму суть Task и всего TPL, стоящего за ним .await, как говорится, это маркер для компилятора, который переписывает ваш метод в старой доброй манере «обратного вызова» (типично a-ka JavaScript), что является асинхронным способом полного завершениято же самое вычисление.

Проще: вы должны предпочесть await над .Result, когда это возможно.

...