Что может вызвать большие накладные расходы на выполнение вызова HttpWebRequest? - PullRequest
5 голосов
/ 08 марта 2010

Когда я отправляю / получаю данные, используя HttpWebRequest (на Silverlight ) в небольших блоках, я измеряю очень маленькую пропускную способность 500 байтов / с в течение соединение "localhost". При отправке данных большими блоками у меня получается 2 МБ / с, что примерно в 5000 раз быстрее .

Кто-нибудь знает, что может вызвать эти невероятно большие накладные расходы?

Дополнительная информация :

  • Я использую метод HTTP POST
  • Я провел измерение производительности как в Firefox 3.6, так и в Internet Explorer 7. Оба показали одинаковые результаты.
  • Мой ЦП загружен всего на 10% (четырехъядерный, так что на самом деле 40%)
  • WebClient показал похожие результаты
  • WCF / SOAP показали аналогичные результаты

Обновление : код на стороне клиента Silverlight, который я использую, по сути является моей собственной реализацией класса WebClient. Я написал это потому, что заметил ту же проблему с производительностью WebClient и подумал, что HttpWebRequest позволит настроить проблему с производительностью. К сожалению, это не сработало. Реализация выглядит следующим образом:

public class HttpCommChannel
{
    public delegate void ResponseArrivedCallback(object requestContext, BinaryDataBuffer response);

    public HttpCommChannel(ResponseArrivedCallback responseArrivedCallback)
    {
        this.responseArrivedCallback = responseArrivedCallback;
        this.requestSentEvent = new ManualResetEvent(false);
        this.responseArrivedEvent = new ManualResetEvent(true);
    }

    public void MakeRequest(object requestContext, string url, BinaryDataBuffer requestPacket)
    {
        responseArrivedEvent.WaitOne();
        responseArrivedEvent.Reset();

        this.requestMsg = requestPacket;
        this.requestContext = requestContext;

        this.webRequest = WebRequest.Create(url) as HttpWebRequest;
        this.webRequest.AllowReadStreamBuffering = true;
        this.webRequest.ContentType = "text/plain";
        this.webRequest.Method = "POST";

        this.webRequest.BeginGetRequestStream(new AsyncCallback(this.GetRequestStreamCallback), null);
        this.requestSentEvent.WaitOne();
    }

    void GetRequestStreamCallback(IAsyncResult asynchronousResult)
    {
        System.IO.Stream postStream = webRequest.EndGetRequestStream(asynchronousResult);

        postStream.Write(requestMsg.Data, 0, (int)requestMsg.Size);
        postStream.Close();

        requestSentEvent.Set();
        webRequest.BeginGetResponse(new AsyncCallback(this.GetResponseCallback), null);
    }

    void GetResponseCallback(IAsyncResult asynchronousResult)
    {
        HttpWebResponse response = (HttpWebResponse)webRequest.EndGetResponse(asynchronousResult);
        Stream streamResponse = response.GetResponseStream();
        Dim.Ensure(streamResponse.CanRead);
        byte[] readData = new byte[streamResponse.Length];
        Dim.Ensure(streamResponse.Read(readData, 0, (int)streamResponse.Length) == streamResponse.Length);
        streamResponse.Close();
        response.Close();

        webRequest = null;
        responseArrivedEvent.Set();
        responseArrivedCallback(requestContext, new BinaryDataBuffer(readData));
    }

    HttpWebRequest webRequest;
    ManualResetEvent requestSentEvent;
    BinaryDataBuffer requestMsg;
    object requestContext;
    ManualResetEvent responseArrivedEvent;
    ResponseArrivedCallback responseArrivedCallback;
}

Я использую этот код для отправки данных туда и обратно на HTTP-сервер.

Обновление : после обширных исследований я пришел к выводу, что проблема производительности присуща Silverlight v3 .

Ответы [ 3 ]

4 голосов
/ 08 марта 2010

Вполне возможно, вы наблюдаете за эффектами алгоритма Nagle, попробуйте:

this.webRequest.UseNagleAlgorithm.ServicePoint = false;

Кроме того, «рукопожатие» Expect100Continue относится к производительности вызовов службы мыла:

this.webRequest.Expect100Continue.ServicePoint = false;

UDPATE:

Только что понял, что ServicePoint недоступен в Compact Framework. Однако вы можете доказать это, выполнив:

ServicePointManager.UseNagleAlgorithm = false

Или изменить настройку релевантности в файле конфигурации приложения, или что-либо еще в эквиваленте Silverlight?

1 голос
/ 08 марта 2010

Как упоминал Майк Диммик в своем ответе, проблема с задержкой может вызвать проблемы, однако помимо проблем с задержкой в ​​случае очень небольших полезных нагрузок данных, выделение потока для выполнения (даже с пулом потоков) сопровождается установлением соединение будет составлять гораздо больший процент от общего времени, чем при маршруте массовой загрузки.

1 голос
/ 08 марта 2010

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

По сути, любой интерфейс, который пересекает коммуникационную границу - будь то межпроцессный или межмашинный - должен быть «коротким», а не «болтливым». Отправляйте как можно больше информации в каждом запросе и получайте в ответ как можно больше данных. На том же компьютере это может показаться тривиальным, но я видел десятикратное улучшение производительности на сервере приложений за счет пакетирования команд в рабочем процессе, а не обратного вызова из рабочего процесса в основной процесс сервера для каждой команды. *

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

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