2016-05-10 2 views
-1

Пожалуйста, посмотрите на этот код:Почему некоторые методы асинхронных выполняются синхронно

class Program 
{ 
    static async void DoStuff() 
    { 
     StreamWriter s = new StreamWriter("a.txt"); 
     WebClient wc = new WebClient(); 
     await wc.DownloadStringTaskAsync(new Uri("http://www.microsoft.com")); //1 
     //await s.WriteAsync ("123");           //2 
     Thread.Sleep(10000); 
     Console.WriteLine("DoStuffEnd"); 
    } 
    static void Main(string[] args) 
    { 
     Program.DoStuff(); 
     Console.WriteLine("MainEnd"); 
     Console.Read(); 
    } 

} 

В этой ситуации все в порядке, в соответствии с логикой асинхронном/ждать.

Выходные:

  • MainEnd

  • Через 10 секунд

  • DoStuffEnd

Но если я комментарий (1) и раскомментируйте (2), выход это:

  • Через 10 секунд

  • DoStuffEnd

  • MainEnd

Почему?

+0

Ваш 'main()' не может "заканчиваться" перед любой другой функцией, потому что это будет «конец» вашей программы. – Nasreddine

+0

К тому времени, когда сгенерированный код 'await' смотрит на задачу, чтобы проверить, завершено ли это, какой в вашем случае для загрузки нет, если к тому времени он уже завершен (как и у вашего случая записи потока), то он просто продолжается синхронно. –

ответ

5

Этот код:

await x 

если x является awaitable (как задача), которая уже завершена, то метод просто продолжает выполнение синхронно, как и обычным способом.

Стивен Клири упоминает об этом в своем блоге:

Async and Await:

«ждут» ключевых слов, где вещи могут получить асинхронный. Ожидание похоже на унарный оператор: он принимает один аргумент, ожидаемый («ожидаемый» - асинхронная операция). Ожидание проверяет, что ожидает, что он уже завершен; , если ожидаемый уже завершен, метод просто продолжает работать (синхронно, как обычный метод).

(курсив мой)

В случае вашей загрузки, то маловероятно, что загрузка завершается так быстро, что задача помечается как полным в (относительно) несколько циклов центрального процессора до момента код достигает ожидания.

Однако, в async write, может быть даже оптимизация, которая говорит, что так и так мелкие записи будут просто выполняться синхронно, потому что накладные расходы async могут затмить фактическую запись, или вы, возможно, почувствуете, что запись выполняется так мало времени, что он завершится до того, как код попытается его подождать.

Следствием является то, что вы должны использовать await Task.Delay(10000); вместо Thread.Sleep(10000);, так как первые будут более «асинхронными».

1

Что происходит, так это то, что StreamWriter уже завершено до того, как среда выполнения проверит, завершена ли она и возвращает управление в основной поток. В этом случае метод async не блокирует, это вызов Thread.Sleep(10000). Чтобы исправить это, попробуйте вместо этого await Task.Delay(10000). Это должно привести к асинхронному коду, который вы ищете.

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