Unsere Web-App läuft in .Net Framework 4.0. Die Benutzeroberfläche ruft Controller-Methoden über Ajax-Aufrufe auf.
Wir müssen den REST-Service unseres Anbieters in Anspruch nehmen. Ich prüfe, wie der REST-Service in .Net 4.0 am besten aufgerufen werden kann. Der REST-Service erfordert ein Standardauthentifizierungsschema und kann Daten sowohl in XML als auch in JSON zurückgeben. Das Hochladen / Herunterladen großer Datenmengen ist nicht erforderlich, und ich sehe in Zukunft nichts mehr. Ich habe mir einige Open-Source-Code-Projekte für den REST-Verbrauch angesehen und in diesen keinen Wert gefunden, um eine zusätzliche Abhängigkeit im Projekt zu rechtfertigen. Begann zu bewerten WebClient
und HttpClient
. Ich habe HttpClient für .Net 4.0 von NuGet heruntergeladen.
Ich habe nach Unterschieden zwischen WebClient
und gesucht HttpClient
und auf dieser Site wurde erwähnt, dass ein einzelner HttpClient gleichzeitige Anrufe verarbeiten und aufgelöstes DNS, Cookie-Konfiguration und Authentifizierung wiederverwenden kann. Ich sehe noch keine praktischen Werte, die wir aufgrund der Unterschiede gewinnen können.
Ich habe einen kurzen Leistungstest durchgeführt, um herauszufinden, wie WebClient
(Synchronisierungsaufrufe), HttpClient
(Synchronisierung und Asynchronisierung) funktionieren . und hier sind die Ergebnisse:
Verwenden derselben HttpClient
Instanz für alle Anforderungen (min - max)
WebClient-Synchronisierung: 8 ms - 167 ms
HttpClient-Synchronisierung: 3 ms - 7228 ms
HttpClient- Synchronisierung : 985 - 10405 ms
Verwenden eines neuen HttpClient
für jede Anforderung (min - max)
WebClient-Synchronisierung: 4 ms - 297 ms
HttpClient-Synchronisierung: 3 ms - 7953 ms
HttpClient-Asynchronisierung: 1027 - 10834 ms
Code
public class AHNData
{
public int i;
public string str;
}
public class Program
{
public static HttpClient httpClient = new HttpClient();
private static readonly string _url = "http://localhost:9000/api/values/";
public static void Main(string[] args)
{
#region "Trace"
Trace.Listeners.Clear();
TextWriterTraceListener twtl = new TextWriterTraceListener(
"C:\\Temp\\REST_Test.txt");
twtl.Name = "TextLogger";
twtl.TraceOutputOptions = TraceOptions.ThreadId | TraceOptions.DateTime;
ConsoleTraceListener ctl = new ConsoleTraceListener(false);
ctl.TraceOutputOptions = TraceOptions.DateTime;
Trace.Listeners.Add(twtl);
Trace.Listeners.Add(ctl);
Trace.AutoFlush = true;
#endregion
int batchSize = 1000;
ParallelOptions parallelOptions = new ParallelOptions();
parallelOptions.MaxDegreeOfParallelism = batchSize;
ServicePointManager.DefaultConnectionLimit = 1000000;
Parallel.For(0, batchSize, parallelOptions,
j =>
{
Stopwatch sw1 = Stopwatch.StartNew();
GetDataFromHttpClientAsync<List<AHNData>>(sw1);
});
Parallel.For(0, batchSize, parallelOptions,
j =>
{
Stopwatch sw1 = Stopwatch.StartNew();
GetDataFromHttpClientSync<List<AHNData>>(sw1);
});
Parallel.For(0, batchSize, parallelOptions,
j =>
{
using (WebClient client = new WebClient())
{
Stopwatch sw = Stopwatch.StartNew();
byte[] arr = client.DownloadData(_url);
sw.Stop();
Trace.WriteLine("WebClient Sync " + sw.ElapsedMilliseconds);
}
});
Console.Read();
}
public static T GetDataFromWebClient<T>()
{
using (var webClient = new WebClient())
{
webClient.BaseAddress = _url;
return JsonConvert.DeserializeObject<T>(
webClient.DownloadString(_url));
}
}
public static void GetDataFromHttpClientSync<T>(Stopwatch sw)
{
HttpClient httpClient = new HttpClient();
var response = httpClient.GetAsync(_url).Result;
var obj = JsonConvert.DeserializeObject<T>(
response.Content.ReadAsStringAsync().Result);
sw.Stop();
Trace.WriteLine("HttpClient Sync " + sw.ElapsedMilliseconds);
}
public static void GetDataFromHttpClientAsync<T>(Stopwatch sw)
{
HttpClient httpClient = new HttpClient();
var response = httpClient.GetAsync(_url).ContinueWith(
(a) => {
JsonConvert.DeserializeObject<T>(
a.Result.Content.ReadAsStringAsync().Result);
sw.Stop();
Trace.WriteLine("HttpClient Async " + sw.ElapsedMilliseconds);
}, TaskContinuationOptions.None);
}
}
}
Meine Fragen
- Die REST-Aufrufe kehren in 3-4 Sekunden zurück, was akzeptabel ist. Aufrufe des REST-Dienstes werden in Controller-Methoden initiiert, die von Ajax-Aufrufen aufgerufen werden. Zunächst werden die Aufrufe in einem anderen Thread ausgeführt und blockieren die Benutzeroberfläche nicht. Kann ich mich also einfach an Synchronisierungsanrufe halten?
- Der obige Code wurde in meiner Localbox ausgeführt. Bei der Prod-Einrichtung werden DNS- und Proxy-Lookup beteiligt sein. Gibt es einen Vorteil der Verwendung von
HttpClient
overWebClient
? - Ist
HttpClient
Parallelität besser alsWebClient
? Aus den Testergebnissen geht hervor, dassWebClient
Synchronisierungsaufrufe eine bessere Leistung erbringen. - Wird
HttpClient
eine bessere Design-Wahl sein, wenn wir auf .Net 4.5 aktualisieren? Leistung ist der entscheidende Designfaktor.
GetDataFromHttpClientAsync
da er zuerst ausgeführt wird. Die anderen Aufrufe profitieren davon, dass möglicherweise Daten gespeichert sind (sei es auf dem lokalen Computer oder einem transparenten Proxy zwischen Ihnen und dem Ziel), und sind schneller. Unter den richtigen Bedingungenvar response = httpClient.GetAsync("http://localhost:9000/api/values/").Result;
kann es auch zu einem Deadlock kommen, da Sie Threadpool-Threads erschöpfen. Sie sollten niemals eine Aktivität blockieren, die vom Thread-Pool in ThreadPool-Threads abhängt. Stattdessen solltenawait
Sie den Thread wieder in den Pool zurückgeben.