Почему WebClient.DownLoadStringTaskasync () блок? - Новый Async API / синтаксис / CTP
-
27-09-2019 - |
Вопрос
По какой-то причине есть пауза после начала программы ниже. я полагаю, что WebClient().DownloadStringTaskAsync()
это причина.
class Program
{
static void Main(string[] args)
{
AsyncReturnTask();
for (int i = 0; i < 15; i++)
{
Console.WriteLine(i);
Thread.Sleep(100);
}
}
public static async void AsyncReturnTask()
{
var result = await DownloadAndReturnTaskStringAsync();
Console.WriteLine(result);
}
private static async Task<string> DownloadAndReturnTaskStringAsync()
{
return await new WebClient().DownloadStringTaskAsync(new Uri("http://www.weather.gov"));
}
}
Насколько я понимаю, моя программа должна немедленно начать рассчитывать от 0 до 15. Я делаю что-то неправильно?
У меня была такая же проблема с оригинальным образцом скачивания Netflix (который вы получаете с CTP.) - После нажатия кнопки поиска пользовательские пользователи First зависают - и через некоторое время он отзывчивый во время загрузки следующих фильмов. И я верю, что он не замерзал в презентации anders Hejlsberg в PDC 2010.
Еще кое-что. Когда вместо
return await new WebClient().DownloadStringTaskAsync(new Uri("http://www.weather.gov"));
Я использую свой собственный метод:
return await ReturnOrdinaryTask();
Который:
public static Task<string> ReturnOrdinaryTask()
{
var t = Task.Factory.StartNew(() =>
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("------------- " + i.ToString());
Thread.Sleep(100);
}
return "some text";
});
return t;
}
Работает как это должно. Я имею в виду, что это ничего не загружает, но он начинается немедленно и не блокирует основной нить, выполняя свою работу.
Редактировать
Хорошо, что я верю прямо сейчас: WebClient.DownloadStringTaskAsync
Функция прикручена вверх. Он должен работать без начального периода блокировки, как это:
static void Main(string[] args)
{
WebClient cli = new WebClient();
Task.Factory.StartNew(() =>
{
cli.DownloadStringCompleted += (sender, e) => Console.WriteLine(e.Result);
cli.DownloadStringAsync(new Uri("http://www.weather.gov"));
});
for (int i = 0; i < 100; i++)
{
Console.WriteLine(i);
Thread.Sleep(100);
}
}
Решение
Хотя ваша программа на некоторое время блокируется, она делает выполнение возобновления в цикле для возврата результата с удаленного сервера.
Помните, что новый Async API все еще однопоточной. Так WebClient().DownloadStringTaskAsync()
Все еще необходимо запустить в своей теме, пока запрос не будет подготовлен и отправлен на сервер, прежде чем он может await
и дайте выполнение обратно к вашему промежуточному потоку в Main ().
Я думаю, что результаты, которые вы видите, связаны с тем, что требуется некоторое время для создания и отправки запроса с вашей машины. Сначала, когда это закончено, реализация DownloadStringTaskAsync
Можете дождаться сети IO и удаленного сервера для завершения и может вернуть вам выполнение.
С другой стороны, ваш RunOrdinaryTask
Метод просто инициализирует задачу и дает ему рабочую нагрузку и говорит ей начать. Тогда он возвращается немедленно. Вот почему вы не видите задержки при использовании RunOrdinaryTask
.
Вот некоторые ссылки на тему: Блог Eric Lippert (один из дизайнеров языка), а также Первоначальный блог Jon Skeet об этом. У Эрика есть серия из 5 постов о продолжании прохождения стиля, который действительно то, что async
и await
на самом деле о. Если вы хотите понять новую функцию подробно, вы можете прочитать посты Eric о CPS и Async. В любом случае, обе ссылки выше, делает хорошую работу по объяснению очень важного факта:
- Асинхронный! = Параллель
Другими словами, async
и await
не раскручивает новые нити для вас. Они просто позволяют вам возобновить выполнение вашего обычного потока, когда вы выполняете операцию блокировки - раз, когда ваш процессор просто сидел и ничего не сделает в синхронной программе, ожидая завершенной внешней операции.
Редактировать
Просто чтобы быть понятно о том, что происходит: DownloadStringTaskAsync
устанавливает продолжение, затем звонки WebClient.DownloadStringAsync
, на той же ните, и потом дает исполнение обратно в ваш код. Следовательно, время блокировки вы видите до того, как цикл начинает подсчитать, это время, которое требуется DownloadStringAsync
завершить. Ваша программа с Async и aNAIT очень близка к эквиваленту следующей программы, которая демонстрирует одно и то же поведение, что и ваша программа: начальный блок, затем счет запускается, а где-то посередине, асинхроздание OP отделки и печатает содержимое от Запрашиваемый 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 прошлой ночью.
Другие советы
Вы уверены, что проблема не связана с настройками конфигурации прокси, обнаруженных из IE / реестра / где-то медленно?
Попробуйте установить WebClient.Proxy = NULL (или указание настроек в App.config), и ваш период «блокировки» должен быть минимальным.
Вы нажимаете F5 или CTLR + F5, чтобы запустить его? С F5 есть задержка для VS просто для поиска символов для AsyncctLibrary.dll ...