Как получить быстрый. Http-запрос .Net

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

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

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

Я получаю приемлемые результаты с 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);
    }

Ответ 1

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

  • Сроки 1: Доминирование на основе JIT, т.е. процесс преобразования байт-кода в собственный код.
  • Сроки 2: Возможный шаг оптимизации для кода JIT'd.

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

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

JIT: 410.79ms

Оптимизировать:. 0.98ms

Среднее более 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;
}

Ответ 2

Используйте StopWatch для получения точных таймингов.

Затем убедитесь, что вы не видите результаты не оптимизированного кода или компиляции JIT, несколько раз проверив свой тест времени в коде Release. Отбросьте первые несколько вызовов, чтобы удалить его влияние 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'd. Он был скомпилирован как debug, но я запустил его без отладки, и получил 63 мс. Я запускаю это на своем ноутбуке Windows 7, поэтому http://localhost возвращает исходную страницу IIS7 по умолчанию. Запустив его снова, я получаю похожие времена.

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

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

Ответ 3

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

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


Обновление 2018: вытягивание этого из комментариев.

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