Laden...

Wie kann man Code wirklich asynchron aufrufen?

Erstellt von cRUSHERHLG vor 4 Jahren Letzter Beitrag vor 4 Jahren 1.455 Views
C
cRUSHERHLG Themenstarter:in
31 Beiträge seit 2018
vor 4 Jahren
Wie kann man Code wirklich asynchron aufrufen?

Ich habe da grundsätzlich die Frage wie man Code wirklich asynchron aufrufen kann.

Im folgenden Code ist die Methodendefinition zwar mit async und Task<string> aber es wird durch das await wieder aufgehoben, sodass es als synchrone Methode ausgeführt wird. Der Grund für den inneren await ist nur wegen der Entfernung der Warnung.


public static async Task<string> Uptime()
        {
            return await Task.Run(() =>
            {
                TimeSpan uptime = TimeSpan.FromMilliseconds(NativeMethods.Kernel32.GetTickCount64());

                string days = uptime.Days + " Days";
                string hours = uptime.Hours + " Hours";
                string minutes = uptime.Minutes + " Minutes";
                string seconds = uptime.Seconds + " Seconds";

                return days + ", " + hours + ", " + minutes + ", " + seconds;
            });
        }

Ich habe mir die Library von Abt (AsyncAll) angeschaut. Soll sie wirklich so funktionieren, das sie auch synchrone Methoden wie z.B. im Code oben dann asynchron ablaufen.
Ist diese noch aktuell sodass man sie noch nutzen kann, da der letzte commit vor über 3 Jahren her ist.

Habe mir zu dem Thema auch mehrere Artikel und Beitrage von Microsoft und co. durchgelesen.
Es ist nur verwirrend, da sich die Erklärungen öfters widersprechen von daher möchte ich fragen welche Quellen man eurerseits als vertrauenswürdig einzustufen sind.

Dazu dann noch ergänzend habt ihr vielleicht selbst Erfahrungen zu dem Thema oder auch Patterns die ihr empfiehlt.

MfG,
cRUSHER

T
2.219 Beiträge seit 2008
vor 4 Jahren

Der Sinn von Abts Lib steckt im Namen und dort werden synchrone Methoden du durch z.B. Action oder andere definierbare Mittel der Sprache durch die TaskFactory.StartNew in einem Task gekapselt und asynchron ausgeführt.
Also genau das Gegenteil von dem was du schreibst.

In einem Beispiel ist das async vermutlich falsch.
Deine Methode sollte, wenn Sie selbst kein await verwendet, schlicht nur einen Task liefern.
Ich habe z.B. bei einem Projekt immer die sychrone Methode mit einer Methode die einfach nur per Task.Run() ein neuen Task liefert ohne async/await umgesetzt.

Somit kann ich auch beide Varianten nutzen, wenn dies den nötig ist.
Ein besserer Ansatz wäre für dich ggf. auch ein Blick in die .NET Sourcen per Reference Code.
In .NET gibt es selbst viele Klasse die sowohl eine synchrone als auch eine asynchrone Methode anbieten.

Es hat sich in den letzten Jahren in dem Bereich auch nicht viel geändert.
Async/Await sind nun mal Sprachkonstrukte mit einem fixen Konzept.
Wenn du diese verstanden hast, kannst du diese auch für dein Zwecke nutzen.

Anbei wären auch Beispiele für Wiedersprüche hilfreich.
Viel falsch kann man eigentlich nicht machen, wenn man es einmal verstanden hat.
Und bei den Beispielen die ich bisher gelesen habe gibt es eigentlich keinen großen Spielraum für falsche Nutzung.
Ansonsten sei auf die Doku verwiesen.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

C
cRUSHERHLG Themenstarter:in
31 Beiträge seit 2018
vor 4 Jahren

Mein Beispiel von oben wie du es schon gesagt hast ist richtig, das es so wie es aktuell ist synchron aufgerufen wird. Es ist sogar noch etwas blöder, da ein Task in einem Task dadurch erstellt wird. Ich wollte mit dem vorgehen nur die Warnung ausbügeln.

Der Grund warum Task.Run im inneren der Methode zu finden ist, da er mir sonst Warnung herausgibt. Kann man diese dann ignorieren?

Kann man die Lib von Abt noch nutzen oder bedarf es einem update da seit 3 Jahren kein neuer commit dazugekommen ist oder hat sich seitdem nichts geändert?

16.792 Beiträge seit 2008
vor 4 Jahren

Den Beispielcode hier asynchron zu machen, ist inhaltlich maximal unsinnig.

Asynchrone Codeausfürhung verwendet man, um Ressourcen zu schonen, die durch ein Blockieren "warten" müssen.
Das ist bei vor allem Fällen bei externer Kommunikation (API Abfragen, Datenbankabfragen, lange Laufzeitberechnugen..) der Fall - niemals bei solch einem simplen Code.

Wenn Du den Code an dieser Stelle unbedingt asynchron machen willst - was unsinnig ist - dann lass das async/await weg - das brauchst Du nicht hier.
Du wartest ja nirgends auf etwas Externes:

public static Task<string> Uptime()
        {
            return Task.Run(() =>
            {
                TimeSpan uptime = TimeSpan.FromMilliseconds(NativeMethods.Kernel32.GetTickCount64());

                string days = uptime.Days + " Days";
                string hours = uptime.Hours + " Hours";
                string minutes = uptime.Minutes + " Minutes";
                string seconds = uptime.Seconds + " Seconds";

                return days + ", " + hours + ", " + minutes + ", " + seconds;
            });
        }

Ich habe mir die Library von Abt (AsyncAll) angeschaut. Soll sie wirklich so funktionieren, das sie auch synchrone Methoden wie z.B. im Code oben dann asynchron ablaufen.

Nein, soll sie nicht. Behaupte ich auch nirgends.

AsyncAll ist ein Wrapper, der genau das macht, was Du hier mit Task.Run() machst.
Ziel ist Kompatibilitäten herzustellen und Übergangslösungen von sync auf async zu schaffen.

zB unterstützt die Win32 API für Dateien bis heute keine einfache Schnittstelle für async/await.
AsyncAll ändert das auch nicht - Du kannst damit aber Problemlos Dein Software Design darauf vorbereiten.

Der Grund warum Task.Run im inneren der Methode zu finden ist, da er mir sonst Warnung herausgibt.

Keiner hier kann hellsehen, von welcher Warnung Du sprichst.

Aber es ist immer eine schlechte Idee "irgendwas zu basteln", statt die Ursache der Meldung zu bekämpfen.

Kann man die Lib von Abt noch nutzen oder bedarf es einem update da seit 3 Jahren kein neuer commit dazugekommen ist oder hat sich seitdem nichts geändert?

Es hat sich nichts geändert. Es gibt aber hier nach dem aktuellen Wissensstand kein Grund, wieso die Lib hier eingesetzt werden sollte - ist unsinnig und nicht Ziel der Lib.

T
2.219 Beiträge seit 2008
vor 4 Jahren

Dein Beispiel ist in diesem Fall falsch.
Damit eine Methode als async markiert werden kann, muss sie intern mindestens einmal await nutzen.
Dies kann aber nur funktionieren, wenn innerhalb der async Methode eben ein Methode aufgerufen wird, die einen Task liefert ohne async Markierung.

Sonst hast du ja das klassische Henne-Ei Problem.
Du willst eine async Methode verwenden ohne await intern zu nutzen.
Und genau dies kreidet dir die Warnung auch an.
Dies funktioniert aber aus dem Konzepten von async/await schon gar nicht.

Beispiele:
https://www.dotnetperls.com/async


public static async void Methode1Async()
{
    // Hier auf den Task von Methode2Async warten.
    await Methode2Async();
}

private static Task Methode2Async()
{
    return Task.Run(() => 
    {
        Methode2();
    });
}

private static void Methode2()
{
    // Hier wird Code ausgewührt der lange laufen kann.
}

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

C
cRUSHERHLG Themenstarter:in
31 Beiträge seit 2018
vor 4 Jahren

Das würde dann heißen, dass ich nach deinem Beispiel sozusagen 3 Implementierung für eine Methode machen müsste. Gibts da nicht auch noch andere Wege wie man es async schafft. Wie würde denn der Code aus der oberen Methode aussehen wenn man ihn nun "richtig" als async methode schreiben möchte?

T
2.219 Beiträge seit 2008
vor 4 Jahren

Mein Beispiel zeigt nur wie die unterste Methode als sync und async genutzt werden kann.
Es würde auch reichen, wenn du nur eine async Methode willst, dass du eben nur die Methode2Async anlegst und dort dann eben die Verarbeitung umsetzt.

Wie gesagt, solltest du dir mal .NET Code anschauen, wie dort die async Methoden umgesetzt wurden.
Wenn deine Methode kein await nutzt, kannst du auch in der Methode kein async in der signatur verwenden.
Du musst dann eben stumpf wie bei meiner Methode2Async einfach einen Task liefern.
Alle Methoden darüber, können dann ein await auf Methode2Async machen und als async markiert werden.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

16.792 Beiträge seit 2008
vor 4 Jahren

Wie würde denn der Code aus der oberen Methode aussehen wenn man ihn nun "richtig" als async methode schreiben möchte?

"Richtig" brauchst Du kein async; Du hast dadurch eher Nachteile als Vorteile.
Es wird eine State Machine erzeugt, die Overhead kostet - und sie wird nicht benötigt.

Es macht nur Sinn, wenn Du es aus Designsicht "brauchst".
Dein Fall wird in den Microsoft-Recommendations unter "do not use async, when..." fallen.

C
cRUSHERHLG Themenstarter:in
31 Beiträge seit 2018
vor 4 Jahren

Generell kann man also sagen, das man async/Tasks nur nutzen sollte, wenn es auch um das Thema I/0 geht wo man sicherstellen will, das man auf Resourcen zugreifen kann, ohne das sie blockiert werden voneinander.

T
2.219 Beiträge seit 2008
vor 4 Jahren

Geht nicht nur um I/O Aufgaben, hatte Abt auch schon oben geschrieben.
Generell kann man Tasks dort verwenden, wo eben auf Resourcen gewartet werden müsste.
Dazu gehört zwar I/O Aufgaben aber auch z.B. auf HTTP Anfragen o.ä.
Ebem langläufige Prozesse die deine Verarbeitung blockieren würden.

Der Sinn ist ja diese asynchron laufen zu lassen, damit die UI weiterarbeiten kann und somit nicht einfriet.
Das ist leider bis heute in vielen Anwendungen immer noch ein großes Problem.
Und genau da setzt async/await eben an um dieses Problemm auf der Ebene der Programmiersprache zu lösen.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

16.792 Beiträge seit 2008
vor 4 Jahren

Dazu gehört zwar I/O Aufgaben aber auch z.B. auf HTTP Anfragen o.ä.

HTTP Anfragen sind I/O 😉

Der Sinn ist ja diese asynchron laufen zu lassen, damit die UI weiterarbeiten kann und somit nicht einfriet.

async/await ist nicht gebunden an die UI.
Es geht grundlegend generell darum, dass eine Verarbeitung nicht blockiert wird. Ob das nun die Verarbeitung der UI ist oder die eines Webservers, die keine UI hat: spielt keine Rolle.
Es geht einfach nur um das Blockieren und das effizientere Nutzen von Ressourcen.

Eine simple synchronous Calculation dahingehend auszulagern, ist keine effiziente Anwendung von async/await.

cRUSHERHLG, auch gerne mal wieder für Dich den Hinweis auf die Doc:
The Task asynchronous programming model in C#
Da sind die Basics.