Как получить быстрый запрос .Net Http - PullRequest
10 голосов
/ 02 декабря 2010

Мне нужен Http-запрос, который я могу использовать в .Net, который занимает менее 100 мс.Я могу добиться этого в своем браузере, так что я действительно не понимаю, почему это такая проблема в коде.

Я пробовал WinHTTP, а также WebRequest.Create, и оба они более 500 мсчто неприемлемо для моего варианта использования.

Вот примеры простого теста, который я пытаюсь пройти.(WinHttpFetcher - это простая оболочка, которую я написал, но она выполняет самый тривиальный пример запроса на получение, который я не уверен, что его стоит вставить.)

Я получаю приемлемые результаты с LibCurlNet, но при одновременном использованиикласса я получаю нарушение прав доступа.Кроме того, поскольку он не является управляемым кодом и должен быть скопирован в каталог bin, его не стоит развертывать вместе с моим проектом с открытым исходным кодом.

Какие-нибудь идеи другой реализации попробовать?

    [Test]
    public void WinHttp_Should_Get_Html_Quickly()
    {
        var fetcher = new WinHttpFetcher();
        var startTime = DateTime.Now;          
        var result = fetcher.Fetch(new Uri("http://localhost"));
        var endTime = DateTime.Now;
        Assert.Less((endTime - startTime).TotalMilliseconds, 100);
    }
    [Test]
    public void WebRequest_Should_Get_Html_Quickly()
    {
        var startTime = DateTime.Now;
        var req = (HttpWebRequest) WebRequest.Create("http://localhost");
        var response = req.GetResponse();
        var endTime = DateTime.Now;
        Assert.Less((endTime - startTime).TotalMilliseconds, 100);
    }

Ответы [ 3 ]

16 голосов
/ 02 декабря 2010

При сравнительном тестировании лучше отбросить как минимум первые два времени, поскольку они могут исказить результаты:

  • Сроки 1: преобладают из-за издержек JIT, т. Е. Процесс преобразования байт-кода в собственный код.
  • Сроки 2: возможный этап оптимизации для кода JIT.

Сроки после этого будут намного лучше отражать повторяемость.

Ниже приведен пример тестового набора, который автоматически игнорирует JIT и этапы оптимизации и запускает тест с заданным количеством итераций, прежде чем принять среднее значение для подтверждения производительности. Как видите, проход JIT занимает значительное время.

JIT: 410.79ms

Оптимизация:. 0.98ms 1020 *

Среднее за 10 итераций: 0,38 мс

Код:

[Test]
public void WebRequest_Should_Get_Html_Quickly()
{
    private const int TestIterations = 10;
    private const int MaxMilliseconds = 100;

    Action test = () =>
    {
       WebRequest.Create("http://localhost/iisstart.htm").GetResponse();
    };

    AssertTimedTest(TestIterations, MaxMilliseconds, test);
}

private static void AssertTimedTest(int iterations, int maxMs, Action test)
{
    double jit = Execute(test); //disregard jit pass
    Console.WriteLine("JIT:{0:F2}ms.", jit);

    double optimize = Execute(test); //disregard optimize pass
    Console.WriteLine("Optimize:{0:F2}ms.", optimize);

    double totalElapsed = 0;
    for (int i = 0; i < iterations; i++) totalElapsed += Execute(test);

    double averageMs = (totalElapsed / iterations);
    Console.WriteLine("Average:{0:F2}ms.", averageMs);
    Assert.Less(averageMs, maxMs, "Average elapsed test time.");
}

private static double Execute(Action action)
{
    Stopwatch stopwatch = Stopwatch.StartNew();
    action();
    return stopwatch.Elapsed.TotalMilliseconds;
}
4 голосов
/ 02 декабря 2010

Используйте класс StopWatch , чтобы получить точные значения времени.

Затем убедитесь, что вы не видите результатов неоптимизированного кода или JIT-компиляции, запустив тест синхронизации несколько раз.в коде релиза.Откажитесь от первых нескольких вызовов, чтобы устранить влияние JIT, а затем усредните все остальные.

VS.NET имеет возможность измерять производительность, и вы также можете использовать что-то вроде Fiddler чтобы узнать, сколько времени вы тратите "на проводе", и проверьте работоспособность, что задержки вызывают не ваш IIS / веб-сервер.

500 мс - это очень много времени, и его можнов 10 секунд мс с этими классами, так что не теряйте надежду (пока).

Обновление № 1:

Это отличная статья, в которой говорится омикро-бенчмаркинг и то, что нужно, чтобы не видеть таких вещей, как JIT:

http://blogs.msdn.com/b/vancem/archive/2009/02/06/measureit-update-tool-for-doing-microbenchmarks.aspx

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

Обновление № 2:

Итак, я написал это консольное приложение (с помощью VS.NET 2010) ...

class Program
{
    static void Main(string[] args)
    {
        var stopwatch = Stopwatch.StartNew();
        var req = (HttpWebRequest)WebRequest.Create("http://localhost");
        var response = req.GetResponse();
        Console.WriteLine(stopwatch.ElapsedMilliseconds);            
    }
}

... и Ctrl-F5 сделал это.Он был скомпилирован как отладочный, но я запустил его без отладки и получил 63ms .Я запускаю это на своем ноутбуке с Windows 7, и поэтому http://localhost возвращает домашнюю страницу IIS7 по умолчанию.Запуская его снова, я получаю аналогичные времена.

Запуск сборки Release дает время в диапазоне от 50 мс до 55 мс .

Это порядоквеличина я бы ожидал.Очевидно, что если ваш веб-сайт выполняет перекомпиляцию ASP.NET, или перезапускает пул приложений, или выполняет много серверной обработки, тогда ваши сроки будут другими.Если ваша разметка огромна, то она также будет отличаться, но ни один из классов, которые вы используете на стороне клиента, не должен быть шагами по ограничению скорости.Это будет надежда сети и / или обработка удаленного приложения.

1 голос
/ 02 декабря 2010

Попробуйте установить для свойства Proxy экземпляра HttpWebRequest значение null. Если это работает, попробуйте установить его в GlobalProxySelection.GetEmptyWebProxy (), что представляется более правильным.

Вы можете прочитать об этом здесь: - Медленный веб-запрос ?: http://holyhoehle.wordpress.com/2010/01/12/webrequest-slow/


Обновление 2018: подтянуть это из комментариев.

System.Net.GlobalProxySelection устарел. Этот класс устарел. Используйте взамен WebRequest.DefaultWebProxy, чтобы получить доступ к глобальному прокси-серверу по умолчанию и установить его. Используйте null вместо GetEmptyWebProxy (). - Джирариум 22 июля 17 года в 5:44

...