HttpClient async-requests nicht den Abschluss für große batch-geschickt in eine Schleife
Ich glaube, ich habe es geschafft, einen test, der zeigt dieses problem wiederholbar, zumindest auf meinem system. Diese Frage bezieht sich auf HttpClient verwendet wird, für eine schlechte Endpunkt (nonexistant Endpunkt, das Ziel ist).
Das problem ist, dass die Anzahl der abgeschlossenen Aufgaben greift zu kurz, die gesamte, in der Regel etwa ein paar. Ich nicht Anfragen, die nicht arbeiten, aber das nur die Ergebnisse in der app nur dort hängen, wenn die Ergebnisse abgewartet werden.
Bekomme ich das folgende Ergebnis form den test-code unten:
Elapsed: 237.2009884 Sekunden.
Aufgaben in der batch-array: 8000 Abgeschlossene Aufgaben : 7993
Wenn ich batchsize zu 8 anstelle von 8000, die es vollendet. Für 8000 es Staus auf der WhenAll .
Ich Frage mich, ob andere Leute das gleiche Ergebnis erhalten, wenn ich etwas falsch machen, und wenn dies scheint ein Fehler zu sein.
using System;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace CustomArrayTesting
{
///<summary>
///Problem: a large batch of async http requests is done in a loop using HttpClient, and a few of them never complete
///</summary>
class ProgramTestHttpClient
{
static readonly int batchSize = 8000; //large batch size brings about the problem
static readonly Uri Target = new Uri("http://localhost:8080/BadAddress");
static TimeSpan httpClientTimeout = TimeSpan.FromSeconds(3); //short Timeout seems to bring about the problem.
///<summary>
///Sends off a bunch of async httpRequests using a loop, and then waits for the batch of requests to finish.
///I installed asp.net web api client libraries Nuget package.
///</summary>
static void Main(String[] args)
{
httpClient.Timeout = httpClientTimeout;
stopWatch = new Stopwatch();
stopWatch.Start();
//this timer updates the screen with the number of completed tasks in the batch (See timerAction method bellow Main)
TimerCallback _timerAction = timerAction;
TimerCallback _resetTimer = ResetTimer;
TimerCallback _timerCallback = _timerAction + _resetTimer;
timer = new Timer(_timerCallback, null, TimeSpan.FromSeconds(1), Timeout.InfiniteTimeSpan);
//
for (int i = 0; i < batchSize; i++)
{
Task<HttpResponseMessage> _response = httpClient.PostAsJsonAsync<Object>(Target, new Object());//WatchRequestBody()
Batch[i] = _response;
}
try
{
Task.WhenAll(Batch).Wait();
}
catch (Exception ex)
{
}
timer.Dispose();
timerAction(null);
stopWatch.Stop();
Console.WriteLine("Done");
Console.ReadLine();
}
static readonly TimeSpan timerRepeat = TimeSpan.FromSeconds(1);
static readonly HttpClient httpClient = new HttpClient();
static Stopwatch stopWatch;
static System.Threading.Timer timer;
static readonly Task[] Batch = new Task[batchSize];
static void timerAction(Object state)
{
Console.Clear();
Console.WriteLine("Elapsed: {0} seconds.", stopWatch.Elapsed.TotalSeconds);
var _tasks = from _task in Batch where _task != null select _task;
int _tasksCount = _tasks.Count();
var _completedTasks = from __task in _tasks where __task.IsCompleted select __task;
int _completedTasksCount = _completedTasks.Count();
Console.WriteLine("Tasks in batch array: {0} Completed Tasks : {1} ", _tasksCount, _completedTasksCount);
}
static void ResetTimer(Object state)
{
timer.Change(timerRepeat, Timeout.InfiniteTimeSpan);
}
}
}
Manchmal ist es einfach abstürzt, vor dem beenden mit einer Zugriffsverletzung nicht behandelte Ausnahme. Der call-stack sagt nur:
> mscorlib.dll!System.Threading._IOCompletionCallback.PerformIOCompletionCallback(uint errorCode = 1225, uint numBytes = 0, System.Threading.NativeOverlapped* pOVERLAP = 0x08b38b98)
[Native to Managed Transition]
kernel32.dll!@BaseThreadInitThunk@12()
ntdll.dll!___RtlUserThreadStart@8()
ntdll.dll!__RtlUserThreadStart@8()
Meisten der Zeit es nicht Abstürzen, aber eben nie beendet, wartet auf die whenall. In jedem Fall sind die folgenden erste-chance-Ausnahmen geworfen werden, für jede Anfrage:
A first chance exception of type 'System.Net.Sockets.SocketException' occurred in System.dll
A first chance exception of type 'System.Net.WebException' occurred in System.dll
A first chance exception of type 'System.AggregateException' occurred in mscorlib.dll
A first chance exception of type 'System.ObjectDisposedException' occurred in System.dll
Machte ich den debugger beenden, die auf das Objekt entsorgt Ausnahme, und habe diese call stack:
> System.dll!System.Net.Sockets.NetworkStream.UnsafeBeginWrite(byte[] buffer, int offset, int size, System.AsyncCallback callback, object state) + 0x136 bytes
System.dll!System.Net.PooledStream.UnsafeBeginWrite(byte[] buffer, int offset, int size, System.AsyncCallback callback, object state) + 0x19 bytes
System.dll!System.Net.ConnectStream.WriteHeaders(bool async = true) + 0x105 bytes
System.dll!System.Net.HttpWebRequest.EndSubmitRequest() + 0x8a bytes
System.dll!System.Net.HttpWebRequest.SetRequestSubmitDone(System.Net.ConnectStream submitStream) + 0x11d bytes
System.dll!System.Net.Connection.CompleteConnection(bool async, System.Net.HttpWebRequest request = {System.Net.HttpWebRequest}) + 0x16c bytes
System.dll!System.Net.Connection.CompleteConnectionWrapper(object request, object state) + 0x4e bytes
System.dll!System.Net.PooledStream.ConnectionCallback(object owningObject, System.Exception e, System.Net.Sockets.Socket socket, System.Net.IPAddress address) + 0xf0 bytes
System.dll!System.Net.ServicePoint.ConnectSocketCallback(System.IAsyncResult asyncResult) + 0xe6 bytes
System.dll!System.Net.LazyAsyncResult.Complete(System.IntPtr userToken) + 0x65 bytes
System.dll!System.Net.ContextAwareResult.Complete(System.IntPtr userToken) + 0x92 bytes
System.dll!System.Net.LazyAsyncResult.ProtectedInvokeCallback(object result, System.IntPtr userToken) + 0xa6 bytes
System.dll!System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(uint errorCode, uint numBytes, System.Threading.NativeOverlapped* nativeOverlapped) + 0x98 bytes
mscorlib.dll!System.Threading._IOCompletionCallback.PerformIOCompletionCallback(uint errorCode, uint numBytes, System.Threading.NativeOverlapped* pOVERLAP) + 0x6e bytes
[Native to Managed Transition]
Ausnahme Nachricht war:
{"Cannot access a disposed object.\r\nObject name: 'System.Net.Sockets.NetworkStream'."} System.Exception {System.ObjectDisposedException}
Beachten Sie die Beziehung, dass unbehandelte Zugriffsverletzung-Ausnahme, die ich nur selten zu sehen.
So, es scheint, dass HttpClient ist nicht robust ist, wenn das Ziel down ist. Ich mache das auf windows 7 32 übrigens.
- Dies erfordert eine beträchtlich lange Zeit zu laufen auf meinem Rechner (892 Sekunden), aber alle 8000 Aufgaben abgeschlossen sind. Vielleicht sind Sie knapp an ephemeral ports?
- Vielen Dank für die läuft es. Vielleicht hat das etwas damit zu tun. Finden Sie heraus, vielleicht über mich. Ich werde führen Sie es wieder nach einem Neustart.
- Bleibt trotzdem das Problem für die größeren Chargen. Ich habe die temporären Ports situation mit einem Skript aus dem technet, und es scheint in Ordnung; nicht sehr viele ports verwendet. Bekomme ich eine unbehandelte Fehler manchmal. Ich aktualisiere die Frage mit ein paar mehr Infos.
- Warum auf der Erde würden Sie wollen, zu laufen, 8000 parallele Aufgaben?
- 8000 Aufgaben nichts, getestet habe ich die task parallel library für Hunderte von tausenden von Aufgaben (die nichts tun) und es funktionierte perfekt, ohne viel Speicher. Für die web-Anfrage, die ich machen möchte 8000 parallel, wenn jeder nimmt sich 1 Sekunden lang, um zu vermeiden, dass Sie die 8000 Sekunden.
- Dieser wurde vor kurzem veröffentlicht. Es kann etwas Licht auf die situation, wenn Sie erfassen ein dump, eine minute und verwenden Sie
!whttp
. - jedes Ding auf dieser Seite entfernt wurde...
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich sah durch die Quelle des HttpClient mit dem Reflektor. Für die synchron ausgeführte Teil der operation (wenn es getreten wird-aus), es scheint kein timeout angewendet, um die zurückgegebenen Aufgabe, soweit ich das sehen kann. Es gibt einige timeout-Implementierung, ruft Abort() auf eine HttpWebRequest-Objekt, aber wieder, scheinen Sie zu übersehen, aus irgendeinem timeout Stornierung oder fehlgeschlagenes der zurückzusendenden Aufgabe auf dieser Seite des async-Funktion. Gibt es vielleicht etwas, was auf der Rückruf-Seite, aber manchmal ist die callback-ist wahrscheinlich "going missing", die zu den führenden zurückgegeben Aufgabe, die nie abgeschlossen werden kann.
Ich habe eine Frage zu Fragen, wie Sie ein Zeitlimit für jede Aufgabe, und ein Beantworter gab dieses sehr schöne Lösung (das hier als eine Erweiterung Methode):
So, Berufung HttpClient wie dieser soll verhindern, dass irgendwelche "Aufgaben gone bad" von never ending:
Ein paar mehr Dinge, die ich denke, dass Anforderungen weniger wahrscheinlich verloren gehen:
1. Die Erhöhung der timeout von 3s auf 30s gestellt, die alle Aufgaben fertig stellen, in der das Programm gepostet, dass ich mit dieser Frage.
2. Erhöhen der Anzahl der gleichzeitigen verbindungen erlaubt, beispielsweise mit dem System.Net.ServicePointManager.DefaultConnectionLimit = 100;
Stieß ich auf diese Frage beim googlen nach Lösungen für ein ähnliches problem vom WCF. Die Reihe von Ausnahmen, die genau das gleiche Muster, das ich sehe. Schließlich über eine Tonne der Untersuchung fand ich einen Fehler in HttpWebRequest, dass HttpClient verwendet. Die HttpWebRequest-ruft in einem schlechten Zustand und sendet nur die HTTP-Header. Es sitzt dann auf eine Antwort warten, die nie gesendet werden.
Ich schon angesprochen habe ein ticket mit Microsoft Verbinden, die Sie hier finden: https://connect.microsoft.com/VisualStudio/feedback/details/1805955/async-post-httpwebrequest-hangs-when-a-socketexception-occurs-during-setsocketoption
Die Einzelheiten sind in dem ticket, aber es erfordert einen asynchronen POST-Anruf von der HttpWebRequest-Klasse, um eine nicht-localhost-Maschine. Ich habe es kopiert, auf Windows 7 .Net 4.5 und 4.6. Die ausgefallene SetSocketOption nennen, was Anlass zu der SocketException, nur nicht auf Windows 7 im Test.
Uns die UseNagleAlgorithm Einstellung bewirkt, dass die SetSocketOption nennen, aber wir können nicht vermeiden, es als WCF schaltet UseNagleAlgorithm und Sie können es nicht stoppen. In der WCF-es erscheint wie eine Zeitüberschreitung aufrufen. Natürlich ist dies nicht toll, wie wir sind, die Ausgaben der 60er Jahre zu warten für nichts.
ASP.NET Web API
macht async-HTTP-posts an einen anderen Dienst. Hin und wieder wird es "Stecken" zu bleiben und keine http-Anfragen ausführen richtig, bis ich neu starten, die app-pool. ich benutzeawait client.PostAsJsonAsync()
Ihre Informationen über die Ausnahme ist, verloren zu gehen in der
WhenAll
Aufgabe. Anstatt, dass, versuchen Sie dies:Diese nutzt die
PropagateExceptions
Erweiterung Methode aus den Parallel Extensions Extras Beispiel-code, um sicherzustellen, dass Informationen über die Ausnahme von den Aufgaben in der batch-Betrieb nicht verloren geht: