Ответ 1
Пока ваша программа блокируется некоторое время, она возобновляет выполнение в цикле for, пока результат не будет возвращен с удаленного сервера.
Помните, что новый асинхронный API по-прежнему однопоточен. Таким образом, WebClient().DownloadStringTaskAsync()
по-прежнему нужно запускать в вашем потоке до тех пор, пока запрос не будет подготовлен и отправлен на сервер, прежде чем он сможет await
и вернуть исполнение в поток вашей программы в Main().
Я думаю, что результаты, которые вы видите, связаны с тем, что для создания и отправки запроса с вашего компьютера требуется некоторое время. Во-первых, когда это завершено, реализация DownloadStringTaskAsync
может дождаться завершения ввода IO сети и удаленного сервера и может вернуть вам выполнение.
С другой стороны, ваш метод RunOrdinaryTask
просто инициализирует задачу и дает ей рабочую нагрузку и сообщает ей, чтобы она начиналась. Затем он немедленно возвращается. Вот почему вы не видите задержку при использовании RunOrdinaryTask
.
Вот несколько ссылок на эту тему: блог Эрика Липперта (один из разработчиков языка), а также Начальный пост в блоге Jon Skeet. У Эрика есть сериал из 5 сообщений о стиле продолжения, который на самом деле является тем, о чем говорят async
и await
. Если вы хотите подробно ознакомиться с новой функцией, вы можете прочитать сообщения Eric о CPS и Async. В любом случае, обе ссылки, приведенные выше, отлично справляются с объяснением очень важного факта:
- Асинхронный!= параллельный
Другими словами, async
и await
не разворачивают новые потоки для вас. Они просто позволяют возобновить выполнение вашего обычного потока, когда вы выполняете операцию блокировки - времена, когда ваш процессор просто сидел и ничего не делал в синхронной программе, ожидая завершения внешней операции.
Изменить
Просто чтобы понять, что происходит: DownloadStringTaskAsync
устанавливает продолжение, затем вызывает WebClient.DownloadStringAsync
, в том же потоке, а затем возвращает выполнение кода. Поэтому время блокировки, которое вы видите перед запуском цикла, - это время, необходимое для завершения DownloadStringAsync
. Ваша программа с асинхронным и ожидающим очень близка к эквиваленту следующей программы, которая проявляет то же поведение, что и ваша программа: начальный блок, затем подсчет начинается и где-то посередине, асинхронный режим завершает и печатает содержимое с запрошенный URL:
static void Main(string[] args)
{
WebClient cli = new WebClient();
cli.DownloadStringCompleted += (sender, e) => Console.WriteLine(e.Result);
cli.DownloadStringAsync(new Uri("http://www.weather.gov")); // Blocks until request has been prepared
for (int i = 0; i < 15; i++)
{
Console.WriteLine(i);
Thread.Sleep(100);
}
}
Примечание. Я никоим образом не специалист по этому вопросу, поэтому я могу ошибаться в некоторых вопросах. Не стесняйтесь исправить мое понимание предмета, если вы считаете, что это неправильно - я просто посмотрел презентацию PDC и сыграл с CTP прошлой ночью.