Ich habe diesen einfachen Code:
public static async Task<int> SumTwoOperationsAsync()
{
var firstTask = GetOperationOneAsync();
var secondTask = GetOperationTwoAsync();
return await firstTask + await secondTask;
}
private async Task<int> GetOperationOneAsync()
{
await Task.Delay(500); // Just to simulate an operation taking time
return 10;
}
private async Task<int> GetOperationTwoAsync()
{
await Task.Delay(100); // Just to simulate an operation taking time
return 5;
}
Toll. dies kompiliert.
Nehmen wir an, ich habe eine Konsolen-App und möchte den obigen Code ausführen (Aufruf von SumTwoOperationsAsync()
)
static void Main(string[] args)
{
SumTwoOperationsAsync();
}
Aber ich habe gelesen, dass ich (wenn ich sync
verwende) die ganze Zeit synchronisieren muss up und down :
Frage : Bedeutet das also, dass meine Main
-Funktion als async
markiert werden sollte?
Nun, es kann kann nicht sein, weil ein Kompilierungsfehler vorliegt:
ein Einstiegspunkt kann nicht mit dem Modifikator 'async' markiert werden
Wenn ich das asynchrone Zeug verstehe, wird der Thread die Funktion Main
eingeben ----> SumTwoOperationsAsync
----> wird beide Funktionen aufrufen und wird raus sein. aber bis zum SumTwoOperationsAsync
Was vermisse ich ?
In den meisten Projekttypen endet Ihr async
"up" und "down" bei async void
Eventhandler oder Rückgabe eines Task
an Ihr Framework.
Konsolen-Apps unterstützen dies jedoch nicht.
Sie können entweder nur ein Wait
für die zurückgegebene Aufgabe ausführen:
static void Main()
{
MainAsync().Wait();
// or, if you want to avoid exceptions being wrapped into AggregateException:
// MainAsync().GetAwaiter().GetResult();
}
static async Task MainAsync()
{
...
}
oder du kannst benutze deinen eigenen Kontext wie den, den ich geschrieben habe :
static void Main()
{
AsyncContext.Run(() => MainAsync());
}
static async Task MainAsync()
{
...
}
Weitere Informationen zu async
Console-Apps finden Sie unter in meinem Blog .
Hier ist der einfachste Weg, dies zu tun
static void Main(string[] args)
{
Task t = MainAsync(args);
t.Wait();
}
static async Task MainAsync(string[] args)
{
await ...
}
Als schnelle und zielgerichtete Lösung:
Sowohl Task.Result als auch Task.Wait ermöglichen keine Verbesserung der Skalierbarkeit bei Verwendung mit E/A, da der aufrufende Thread blockiert bleibt und auf das Ende der E/A wartet.
Wenn Sie .Result für eine unvollständige Aufgabe aufrufen, muss der Thread, der die Methode ausführt, warten, bis die Aufgabe abgeschlossen ist. Dadurch wird der Thread daran gehindert, in der Zwischenzeit andere nützliche Aufgaben auszuführen. Dies negiert den Vorteil der Asynchronität der Aufgabe.
Meine Lösung. Der JSONServer ist eine Klasse, die ich geschrieben habe, um einen HttpListener-Server in einem Konsolenfenster auszuführen.
class Program
{
public static JSONServer srv = null;
static void Main(string[] args)
{
Console.WriteLine("NLPS Core Server");
srv = new JSONServer(100);
srv.Start();
InputLoopProcessor();
while(srv.IsRunning)
{
Thread.Sleep(250);
}
}
private static async Task InputLoopProcessor()
{
string line = "";
Console.WriteLine("Core NLPS Server: Started on port 8080. " + DateTime.Now);
while(line != "quit")
{
Console.Write(": ");
line = Console.ReadLine().ToLower();
Console.WriteLine(line);
if(line == "?" || line == "help")
{
Console.WriteLine("Core NLPS Server Help");
Console.WriteLine(" ? or help: Show this help.");
Console.WriteLine(" quit: Stop the server.");
}
}
srv.Stop();
Console.WriteLine("Core Processor done at " + DateTime.Now);
}
}