2010-10-30 8 views
15

По какой-то причине после запуска программы начинается пауза. Я считаю, что причиной является WebClient().DownloadStringTaskAsync().Зачем нужен WebClient.DownloadStringTaskAsync()? - новый асинхронный API/синтаксис/CTP

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) - после нажатия кнопки поиска пользовательский интерфейс сначала замерзает - и через некоторое время он реагирует при загрузке следующих фильмов. И я считаю, что это не замерзло в презентации Андерса Хейльсберга на 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); 
     } 
    } 

ответ

15

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

Помните, что новый асинхронный API по-прежнему является однопоточным. Так что WebClient().DownloadStringTaskAsync() все равно нужно запускать на вашем потоке до тех пор, пока запрос не будет подготовлен и отправлен на сервер, прежде чем он сможет await и вернется к потоку вашей программы в Main().

Я думаю, что результаты, которые вы видите, связаны с тем, что требуется некоторое время для создания и отправки запроса с вашего устройства. Сначала, когда это закончится, реализация DownloadStringTaskAsync может дождаться завершения ввода IO сети и удаленного сервера и может вернуть выполнение вам.

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

Вот несколько ссылок на эту тему: Eric Lippert's blog (один из разработчиков языка), а также об этом Jon Skeet's initial blog post. У Эрика есть сериал из 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 прошлой ночью.

+0

Да, я вижу, что он работает так, как вы сказали - но я верю, что это какая-то ошибка. Идея заключается в том, что асинхронные операции, такие как DownloadStringTaskAsync(), не блокируют основной/ui/вызывающий поток - все, что принимает некоторые время должно быть запущено на другом потоке и немедленно вернуться (иначе - в чем смысл?). Поэтому возникает вопрос: я что-то делаю неправильно или метод DownloadStringTaskAsync() запутан - я знаю, что это ctp/prototype прямо сейчас. Но странно, что в ходе презентации казалось, что на компьютере Хейльсберга он работал нормально (без первоначальной блокировки). – agend

+0

Кто-нибудь может проверить этот код на своем компьютере и подтвердить начальное поведение блокировки? TIA Arek – agend

+0

@agend, я запускал это на своей собственной машине, и я вижу начальное поведение блокировки. – driis

2

Вы используете клавиши F5 или CTLR + F5 для запуска? С F5 существует задержка для VS только для поиска символов для AsyncCtpLibrary.dll ...

+0

f5 или ctrl + f5 не имеет значения - работает одинаково - задержка составляет около 5 секунд, поэтому я не думаю, что это символы имеют значение. У меня такое же поведение в wpf netflix_async_with_await примере u get with cts. – agend

+0

версия этого примера, похоже, работает отлично - она ​​не замерзает изначально - но по какой-то причине она не отображает значки фильмов. – agend

+0

Когда вы запускаете проект silverlight локально, он будет показывать только изображения, если это часть проекта/веб-сайта ASP. –

5

Вы уверены, что проблема не связана с параметрами настройки прокси-сервера, обнаруженными из IE/Registry/Somewhere Slow?

Попробуйте установить webClient.Proxy = null (или указать параметры в app.config), и ваш период блокировки должен быть минимальным.

+0

У меня была именно эта проблема –