Я пытаюсь отправлять веб-запросы асинхронно. Мой код работает нормально, за исключением одной вещи: встроенного способа указания времени ожидания для BeginGetResponse
не существует. Пример MSDN ясно показывает рабочий пример, но недостатком является то, что все они заканчиваются
SomeObject.WaitOne()
Который снова ясно заявляет, что он блокирует поток. Я буду в среде с высокой нагрузкой и не смогу блокировать, но мне также нужно тайм-аут запроса, если он занимает более 2 секунд. Если не считать создание отдельного пула потоков и управление им, есть ли в фреймворке что-то, что может мне помочь?
Исходные примеры:
Мне бы хотелось, чтобы асинхронный обратный вызов на BeginGetResponse()
вызывался после истечения срока действия моего параметра timeout с некоторым указанием на то, что тайм-аут произошел.
Кажущийся очевидным параметр TimeOut
не учитывается при асинхронных вызовах.
Параметр ReadWriteTimeout
не вступает в игру, пока не вернется ответ.
Непатентованное решение было бы предпочтительным.
EDIT:
Вот что я придумала: после вызова BeginGetResponse
я создаю Timer
с моей продолжительностью, и это конец фазы «начала» обработки. Теперь либо запрос будет завершен, и моя «конечная» фаза будет вызвана, либо истекает период ожидания.
Чтобы определить гонку и получить единственного победителя, я называю увеличение счетчика «завершено» потокобезопасным способом. Если «тайм-аут» - это первое возвращаемое событие, я отменяю запрос и останавливаю таймер. В этой ситуации, когда вызывается «конец», EndGetResponse
выдает ошибку. Если фаза «конец» наступает первой, счетчик увеличивается, а «тайм-аут» отменяет прерывание запроса.
Кажется, это работает так, как я хочу, и одновременно предоставляет настраиваемое время ожидания. Недостатком является дополнительный объект таймера и обратные вызовы, которых я стараюсь избегать. Я вижу 1-3 потока, обрабатывающих различные части (начало, время ожидания, конец), поэтому кажется, что это работает. И у меня нет никаких звонков "ожидания".
Я пропустил слишком много сна или нашел способ обслуживать свои запросы без блокировки?
int completed = 0;
this.Request.BeginGetResponse(GotResponse, this.Request);
this.timer = new Timer(Timedout, this, TimeOutDuration, Timeout.Infinite);
private void Timedout(object state)
{
if (Interlocked.Increment(ref completed) == 1)
{
this.Request.Abort();
}
this.timer.Change(Timeout.Infinite, Timeout.Infinite);
this.timer.Dispose();
}
private void GotRecentSearches(IAsyncResult result)
{
Interlocked.Increment(ref completed);
}