Laden...

Ausführung ans GUI delegieren per async+await oder per Thread+Control.Invoke

Erstellt von uNki vor 10 Jahren Letzter Beitrag vor 10 Jahren 3.032 Views
Hinweis von herbivore vor 10 Jahren

Abgeteilt von async/await: Verständnisfrage zur Ausführung in synchronen Methoden

U
uNki Themenstarter:in
58 Beiträge seit 2011
vor 10 Jahren

hi!

da meine frage thematisch ganz gut in diesen thread passt, mache ich keinen neuen auf.

ich habe ein label in der statusleiste meiner applikation. dies zeigt einfach nur die uhrzeit an und wird sekündlich aktualisiert. normalerweise würde ich einfach einen timer nehmen, interval auf 1000ms setzen und das label entsprechend aktualisieren.

ich möchte aber "am ball bleiben" und versuche es daher mal mit async/await.

im konstruktor der form rufe ich diese methode auf:


private async void RefreshDateTimeLabel()
        {            
            while (true)
            {
                await Task.Delay(1000);
                lblDateTime.Caption = String.Format("{0} {1}", DateTime.Now.Date.ToLongDateString(), DateTime.Now.ToLongTimeString());
            }
        }

zum verständnis: ich könnte das auch mit einem thread machen, hat das dann den gleichen effekt/technischen hintergrund wie die async/await methode oben?


private void RefreshDateTime()
        {
            Thread thread = new Thread(delegate()
            {
                while (true)
                {
                    if (this.InvokeRequired)
                    {
                        this.Invoke(new MethodInvoker(delegate()
                        {
                            Task.Delay(1000);
                            lblDatumUhrzeit.Caption = String.Format("{0} {1}", DateTime.Now.Date.ToLongDateString(), DateTime.Now.ToLongTimeString());
                        }));
                    }
                }
            });
            thread.Start();
        }

wenn ja, ist das async/await procedere ja wesentlich bequemer und lesbarer 😃

danke und beste grüße!

49.485 Beiträge seit 2005
vor 10 Jahren

Hallo uNki,

die Thread-Variante sollte man sinnvollerweise verändern/verkürzen zu (evtl. mit Control.BeginInvoke statt Control.Invoke):

private void RefreshDateTime()
{
    new Thread(() =>  {
        while (true) {
            Thread.Sleep(1000);
            this.Invoke((Action)(() => {
                lblDatumUhrzeit.Caption = String.Format("{0} {1}", DateTime.Now.Date.ToLongDateString(), DateTime.Now.ToLongTimeString());
            }));
        }
    }).Start ();
}

Erst damit hast du den gerechten Vergleich zu:


private async void RefreshDateTimeLabel()
        {            
            while (true) {
                await Task.Delay(1000);
                lblDateTime.Caption = String.Format("{0} {1}", DateTime.Now.Date.ToLongDateString(), DateTime.Now.ToLongTimeString());
            }
        }

Welche der beiden Varianten dann lesbarer ist, ist Geschmackssache. Die async-await-Variante ist etwas kürzer, dafür passiert alles implizit (und etwas magisch). Bei der Thread-Variante passiert das wechselseitige Delegieren zwischen den Threads explizit und damit möglicherweise leichter nachvollziehbar. Aber das ist wie gesagt Ansichtssache.

Wie du allerdings richtig sagst, würde man regelmäßige Aktionen im GUI-Thread sowieso am sinnvollsten mit System.Windows.Forms.Timer ausführen.

BTW: Man sollte DateTime.Now nicht zweimal aufrufen, weil sonst um Mitternacht die Zeit möglicherweise nicht zum Datum passt, sondern sich DateTime.Now einmal in einer Variable merken und diese zweimal verwenden.

herbivore

U
uNki Themenstarter:in
58 Beiträge seit 2011
vor 10 Jahren

hallo herbivore,

danke für die erläuterungen und den tipp mit dem datetime.now!

du sagst, es wäre am sinnvollsten das mit einem system.windows.forms.timer zu realisieren.

gibt es hier auch eine begründung?

danke und beste grüße!

4.931 Beiträge seit 2008
vor 10 Jahren

Hallo uNki,

regelmäßige Aktionen, deren Hauptaufwand in der Aktualisierung der GUI liegen, sind eindeutig besser mit einem Timer auszuführen, da diese ja schon selbst im GUI-Thread ablaufen (und daher kein eigener Thread sowie GUI-Synchronisierung notwendig ist).
Nur wenn Berechnungen länger als 50-100ms brauchen (je Tick) oder aber in nicht vorhersehbaren Zeitabschnitten aktualisiert werden müssen, so sind Threads (bzw. Tasks) besser, s.a. [FAQ] Warum blockiert mein GUI?

U
uNki Themenstarter:in
58 Beiträge seit 2011
vor 10 Jahren

danke!