C# multithreading, warten ohne GUI zu blockieren?
Hallo zusammen.
ich habe ein kleines Programm, wo es unter Umständen dazu kommen kann, dass diverse Sachen nacheinander abgearbeitet werden und dort jeweils verschieden lange und gewollte "Sleeps" zum Tragen kommen.
Dazu benutze ich momentan eine kleine Methode:
private void WaitForX(int x)
{
are.WaitOne(x);
}
wobei are folgendes Objekt ist:
private AutoResetEvent are = new AutoResetEvent(false);
Das funktioniert natürlich auch so wie es soll, allerdings blockiert es dann teils die GUI doch für einen erheblichen Zeitraum.
Ich könnte das Problem zwar mit einem Timer beheben, allerdings gibt es mehrere Zwischenschritte, die Methode wird also mehrfach mit unterschiedlichsten Wartezeiten aufgerufen. Bei einem Timer müsste ich dann doch schon ein bisschen rumfrickeln.
Nun die Frage - könnte man das mit einem weiteren Thread lösen? 1 Thread für die GUI (mit Hotkeys und allem) und einen Thread quasi nur als Worker? Wenn ja, wie macht man das?
2 Antworten
Es gibt die BackgroundWorker-Klasse, die du nutzen kannst.
https://docs.microsoft.com/de-de/dotnet/api/system.componentmodel.backgroundworker?view=net-6.0
Grundsätzlich kannst du einen Thread verwenden zB den Bereits genannten BackgroundWorker, aber du kannst das ganze auch mit Async und Await lösen was unter Umständen effektiver ist bzw der "neue Weg" ist so etwas zu lösen.
Der BackgroundWorker erstellt in jedem Fall einen Thread. Bei der Nutzung von async/await ist das im besten Fall nicht notwendig. Genauer gesagt bestimmt die auszuführende Operation, was im Folgenden geschieht. I/O-Operationen bspw. können unabhängig von der CPU laufen, andere Operationen lassen sich aufstückeln und in einer Event Queue abarbeiten oder es wird doch ein Thread beansprucht (sei es ein neuer oder bestehender).
Wenn deine UI durch async/await blockiert wird, wäre anzunehmen, dass du die Technik nicht richtig nutzt, also bspw. keinen Code mit await aufschiebst.
Wenn deine UI durch async/awaitblockiert wird, wäre anzunehmen, dass du die Technik nicht richtig nutzt, also bspw. keinen Code mitawaitaufschiebst.
Ich hatte es nicht ausprobiert, nur kurz online geguckt, was es damit auf sich hatte. Bei dem Code ließ es mich vermuten, dass es nicht unabhängig der GUI läuft. Aber ich hatte ehrlich gesagt mich auch nicht richtig damit beschäftigt sondern auch die Antwort von Peter gewartet. ^^
Nein die GUI Blockiert nicht, dass ist ja der Sinn von Async Await.
Im Hintergrund verwendet das ganze eine Art State Machine die im wesentlichen nicht immer einen eigenen Thread benötigt.
Also wenn zB auf IO Operationen gewartet wird braucht man da keinen Thread welcher im Hintergrund einfach nur wartet, das geht auch wenn man einfach weitermacht und sobald die IO Operation fertig ist dann diesen Code ausführt, das geht dann zB auf einem Thread.
Zudem finde ich persönlich die Async Await Methoden einfach besser lesbar.
Für reine Berechnungen die nicht auf etwas warten sondern einfach nur viel Rechenleistung brauchen machts aber keinen wirklichen Unterschied ob Backgroundworker oder Async.
Hmm, mal schauen ob euch richtig verstanden habe.
Kann ich einfach eine Methode wie z. B.
public static async Task EndlessLoop()
{
await Task.Run(() =>
{
while(true)
{
Console.WriteLine("Still running");
WaitForX(1000); //wait 1 second
}
});
}
aufrufen, ohne dass diese das restliche Programm blockiert und bekomme obendrein den Vorteil, dass der Compiler selbst entscheidet ob er einen zusätzlichen Thread braucht oder nicht?
Ja sofern du die async Methode entsprechend aufrufst und verwendest. Es gibt dazu eigenen Tutorials.
In dem Fall sagst du aber dem Compiler explizit dass er einen Task erstellen soll.
Wenn du aber zB in deiner Methode await Task.Delay(1000); aufrufst dann kommt es drauf an wie Delay implementiert ist. Wenn Delay aber einen Timer verwendet dann benötigt es keinen Thread für Busy Waiting.
Wieso "der neue Weg"? Was stimmt mit dem "alten" nicht? ^^
Und es sieht mir so aus, als ob die GUI dann trotzdem noch blockiert werden würde, oder nicht?