Почему WebClient.DownLoadStringTaskasync () блок? - Новый Async API / синтаксис / CTP

StackOverflow https://stackoverflow.com/questions/4057926

Вопрос

По какой-то причине есть пауза после начала программы ниже. я полагаю, что 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 ...

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top