.NET HttpWebRequest Скорость против браузера - PullRequest
9 голосов
/ 12 января 2010

У меня есть вопрос, касающийся производительности клиента .Net HttpWebRequest (или WebClient, который дает аналогичные результаты).

Если я использую HttpWebRequest для запроса html-страницы (в данном случае news.bbc.co.uk) и анализирую скорость (с помощью HttpAnalyzer), с которой приложение читает ответ, это значительно медленнее, чем браузер ( Firefox, Chrome, IE) запрашивающий один и тот же ресурс (все кэши очищены и т. Д.). Приложение .Net занимает примерно 1,7 секунды против 0,2 - 0,3 секунды для браузера.

Это только из-за скорости и эффективности кода / приложения или есть какие-то другие факторы, которые следует учитывать?

Код следующий:

HttpWebRequest request = null;

Uri uriTest = new Uri("http://news.bbc.co.uk");

request = (HttpWebRequest)WebRequest.Create(uriTest);

request.Method = "GET";
request.KeepAlive = true;
request.Headers["Accept-Encoding"] = "gzip, deflate";

HttpWebResponse response = (HttpWebResponse)request.GetResponse();

response.Close();

Ответы [ 9 ]

2 голосов
/ 12 октября 2010

При первом запросе страницы .net пытается определить настройки прокси. Решение состоит в том, чтобы передать пустой объект WebProxy. Таким образом, он просто подключается к удаленному серверу, а не автоматически определяет прокси-сервер.

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uriTest);
request.Proxy = new WebProxy();
2 голосов
/ 12 января 2010

Если вы делаете два запроса, происходит ли второй быстрее?

Я также заметил разницу в скорости между браузерами и WebClient или WebRequest. Даже грубая скорость ответа может быть радикально различной - но не всегда!

Есть несколько причин, по которым это может быть вызвано:

  • Это может быть все, что происходит при загрузке .Net. Сборки .Net не загружаются и не JITted до тех пор, пока они не используются, поэтому вы можете увидеть значительное снижение скорости при первоначальном обращении к коду кода, даже если само приложение работало целую вечность. Хорошо - значит, сама платформа .Net является nGen'd, но между вашим кодом и платформой .Net все еще есть мост, который можно построить на лету.

  • Просто проверьте, что вы работаете без подключенного отладчика и что у вас определенно не включен сервер символов - сервер символов и VS прерывает программы по мере загрузки символов, замедляя их загрузку. Извините, если это оскорбление;)

  • Браузеры закодированы, чтобы эффективно использовать только несколько базовых сокетов; и они будут открыты и заполнены, как только браузер будет там. «Наш» код, использующий .Net WebClient / WebRequest, совершенно неэффективен в сравнении, поскольку каждый раз все инициализируется заново.

  • Существует множество ресурсов платформы, связанных с сетью, и, хотя .Net значительно упрощает кодирование в сетях, он все еще связан с теми же проблемами с ресурсами платформы. Следовательно, чем ближе вы к платформе, тем быстрее будет какой-то код. IE и Firefox и др. Являются родными и, следовательно, могут естественным образом распределять системные ресурсы; .Net нет, и поэтому для его настройки требуется некоторая сортировка (= медленно). Очевидно, что как только порт открыт и используется, .Net все еще не является дураком; но это почти никогда не будет так быстро, как хорошо написанный немаршалированный нативный код.

1 голос
/ 12 января 2010

Запустите приложение с помощью Ctrl + F5 вместо F5 (режим отладки). Вы увидите разницу:

class Program
{
    static void Main()
    {
        using (var client = new WebClient())
        {
            Stopwatch watch = Stopwatch.StartNew();
            var data = client.DownloadData("http://news.bbc.co.uk");
            watch.Start();
            Console.WriteLine("{0} ms", watch.ElapsedMilliseconds);
        }
    }
}

Печать 880 мс на моем ПК.

1 голос
/ 12 января 2010

Что такое поломка этих 1,7? Я подозреваю, что вы измеряете весь процесс?

Используя этот фрагмент кода, я получаю в среднем около 200 мс:

var request = (HttpWebRequest)WebRequest.Create("http://www.bbc.co.uk/news/");

var stopwatch = new Stopwatch();
stopwatch.Start();

using (var response = (HttpWebResponse)request.GetResponse())
{
    stopwatch.Stop();
    Console.WriteLine("Elapsed: {0}ms", stopwatch.ElapsedMilliseconds);

    var responseStream = response.GetResponseStream();
    if (responseStream != null)
        using (var sr = new StreamReader(responseStream))
            Console.WriteLine("Title: {0}", Regex.Match(sr.ReadToEnd(), @"title>(.*)</title").Groups[1].Value);
}

Изменить изменил код только для измерения фактического HTTP-запроса и повторил попытку, используя Fiddler:

Программа выше: Истекла: 78мс

Скрипач: Всего прошло: 00: 00: 00.0620000

1 голос
/ 12 января 2010

Я бы нажал Fiddler посередине, запустил запрос браузера и запрос .NET один за другим и убедился, что вы действительно получаете то, что думаете. Вполне возможно, что происходит перенаправление или что-то другое (возможно, браузер предварительно добавляет '/', в то время как .NET ожидает перенаправления и т. Д.), Что не сразу видно. Я построил огромные приложения на .NET HTTP-клиенте, не похожем на то, что вы описываете, должно быть что-то еще.

Что произойдет, если вы добавите '/' в конце URL?

1 голос
/ 12 января 2010

Вы смотрели сеть во время использования браузера? Возможно, браузер использует кэшированные ресурсы?

0 голосов
/ 01 августа 2012

Ответ Маркоса отлично сработал для меня в том же вопросе:

request.Proxy = new WebProxy();

Уменьшен 16-секундный запрос до менее чем секунды. Спасибо!

0 голосов
/ 14 января 2010

Всякий раз, когда вы измеряете что-либо, вы должны учитывать начальные затраты. Если ваш код .net находится в одном процессе, и вы измеряете только один запрос, то ваши измерения будут испорчены первыми затратами на инициализацию сборок, типов и т. Д.

Как предположили Дарин и другие, вы должны убедиться, что:

1) Вы не запускаете процесс под отладчиком. 2) Вы учитываете начальные затраты.

Один из способов сделать # 2 - это сделать два запроса и измерить только второй. Или вы можете сделать N запросов, отказаться от 1-го и получить среднее значение по последним N-1 запросам. Также убедитесь, что вы читаете поток сущностей.

0 голосов
/ 12 января 2010

Может быть, bbc.co.uk проверяет заголовок User-Agent , который ему передается, и обрабатывает ответ, основанный на этом. Так что, если он видит автоматизированных клиентов, он реагирует медленно, а если он считает, что в конце строки находится реальный человек, то он ускоряется. Если вы действительно хотите попробовать это, просто скажите HttpWebRequest, чтобы он пропустил другой заголовок.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...