Когда я отправляю/получаю использованию данных HttpWebRequest (на Silverlight) в маленьких блоках, я измеряю очень маленькую пропускную способность 500 байтов/с по "localhost" соединению. При отправке данных в больших блоках я получаю 2 МБ/с, который приблизительно в 5000 раз быстрее.
Кто-либо знает то, что могло вызвать эти невероятно большие издержки?
Дополнительная информация:
Обновление: 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.
Вполне возможно, вы наблюдаете эффекты алгоритма Нагла, попробуйте:
this.webRequest.UseNagleAlgorithm.ServicePoint = false;
Также, "рукопожатие" Expect100Continue имеет отношение к производительности вызова мыльного сервиса:
this.webRequest.Expect100Continue.ServicePoint = false;
UDPATE:
Только что понял, что ServicePoint недоступен в Compact Framework. Однако вы можете доказать это, сделав:
ServicePointManager.UseNagleAlgorithm = false
Или изменив соответствующую настройку в конфигурационном файле приложения, или что там у вас в silverlight?
.Как упомянул Майк Диммик в своем ответе, проблема с задержкой может вызвать проблемы, однако, помимо проблем с задержкой в случае очень малых полезных данных, выделение поток для выполнения (даже с пулом потоков) с последующим установлением соединения будет составлять гораздо больший процент от общего затраченного времени, чем при массовом маршруте полезной нагрузки.
Я подозреваю, что ваша проблема просто в задержке. Любому сообщению требуется некоторое время, чтобы добраться до сервера, чтобы оно было проанализировано, обработано и сгенерировано ответ, а ответу требуется некоторое время, чтобы вернуться к клиенту и преобразовать его в пригодный для использования ответ. В вашей производительности, скорее всего, будет преобладать время прохождения туда и обратно.
По сути, любой интерфейс, пересекающий границу взаимодействия - будь то межпроцессный или межмашинный - должен быть «коротким», а не «болтливым». Отправляйте как можно больше информации в каждом запросе и получайте как можно больше данных в ответ. Это может показаться тривиальным на той же машине, но я увидел десятикратное улучшение производительности на сервере приложений за счет пакетирования команд в рабочем процессе, вместо того, чтобы выполнять обратный вызов из рабочего процесса в процесс главного сервера для каждой команды.
Вы действительно ответили на свой вопрос, указав, что вы получаете гораздо лучшую производительность при использовании блоков большого размера.