Ich muss einen Thread erstellen, der das Foto im Fenster Windows Forms ersetzt, und dann auf ~ 1 Sekunde
Ich dachte, dass der folgende Code:
%Vor%mache den Job, aber leider nicht. Es friert den Haupt-UI-Thread ein.
Das liegt daran, dass nicht garantiert ist, dass es einen Thread pro Aufgabe gibt. Ein Thread kann zur Bearbeitung mehrerer Aufgaben verwendet werden. Sogar TaskCreationOptions.LongRunning Option kann Hilf mir nicht.
Wie kann ich es beheben?
Thread.Sleep ist eine synchrone Verzögerung . Wenn Sie eine asynchrone Verzögerung möchten, verwenden Sie < em> Aufgabe.Delay .
In C # 5, das derzeit in der Beta-Version ist, können Sie einfach
sagen %Vor%in einer asynchronen Methode, und die Methode wird automatisch dort fortgesetzt, wo sie aufgehört hat.
Wenn Sie nicht C # 5 verwenden, können Sie "manuell" den Code einstellen, den Sie selbst als Fortsetzung der Verzögerung verwenden möchten.
Wenn Sie einen neuen TaskScheduler übergeben, der aus dem aktuellen Synchronisationskontext stammt, weisen Sie die Task an, dass sie im UI-Thread ausgeführt werden soll. Sie möchten das tatsächlich tun, also können Sie die UI-Komponente aktualisieren, jedoch möchten Sie nicht in diesem Thread schlafen, da es blockieren wird.
Dies ist ein gutes Beispiel dafür, wenn .ContinueWith
ideal ist:
BEARBEITEN (Etwas entfernt und hinzugefügt):
In diesem Fall blockieren wir den UI-Thread nur so lange, bis pic.Image
aktualisiert wurde. Wenn Sie TaskScheduler
angeben, sagen Sie ihm, in welchem Thread die Aufgabe ausgeführt werden soll. Es ist wichtig zu wissen, dass die Beziehung zwischen Aufgaben und Threads nicht 1: 1 ist. Tatsächlich können 1000 Aufgaben mit relativ wenigen Threads ausgeführt werden, 10 oder weniger sogar, alles hängt von der Menge an Arbeit ab, die jede Aufgabe hat. Gehen Sie nicht davon aus, dass jede Aufgabe, die Sie erstellen, in einem separaten Thread ausgeführt wird. Die CLR leistet einen hervorragenden Job, um die Leistung automatisch für Sie auszugleichen.
Nun müssen Sie nicht mehr den Standard TaskScheduler
verwenden, wie Sie gesehen haben. Wenn Sie die UI TaskScheduler
übergeben, also TaskScheduler.FromCurrentSynchronizationContext()
, verwendet sie den UI-Thread anstelle des Thread-Pools, wie es TaskScheduler.Default
tut.
Denken wir daran, den Code noch einmal zu überprüfen:
%Vor% Hier erstellen und starten wir eine Aufgabe, die auf dem Thread UI ausgeführt wird und die Eigenschaft Image
von pic
mit Ihrer Ressource aktualisiert. Während dies geschieht, reagiert die UI nicht mehr. Glücklicherweise ist dies eine sehr schnelle Operation, die der Benutzer nicht bemerkt.
Mit diesem Code rufen wir die Methode ContinueWith
auf. Es macht genau das, wonach es sich anhört. Es gibt ein neues Task
-Objekt zurück, das den lambda-Parameter ausführt, wenn es ausgeführt wird. Es wird gestartet, wenn die Aufgabe abgeschlossen, fehlerhaft oder abgebrochen wurde. Sie können steuern, wann es ausgeführt wird, indem Sie TaskContinuationOptions
übergeben. Wir übergeben jedoch auch einen anderen Taskplaner wie zuvor. Dies ist der Standard-Aufgabenplaner, der eine Aufgabe in einem Thread-Pool-Thread ausführt und somit die Benutzeroberfläche NICHT blockiert. Diese Aufgabe kann stundenlang ausgeführt werden und Ihre Benutzeroberfläche bleibt reaktiv (lassen Sie es nicht zu), da es sich um einen separaten Thread handelt, mit dem Sie interagieren.
Wir haben auch ContinueWith
für die Aufgaben aufgerufen, die wir für die Ausführung im Standard-Taskplaner festgelegt haben. Dies ist die Aufgabe, die das Bild im Benutzeroberflächenthread erneut aktualisiert, da wir denselben Taskplaner für die Benutzeroberfläche an die ausführende Task übergeben haben. Sobald der Threadpool-Task beendet ist, ruft er diesen im UI-Thread auf und blockiert ihn für eine sehr kurze Zeit, während das Image aktualisiert wird.
Sie sollten Timer
verwenden, um zu einem späteren Zeitpunkt eine UI-Aufgabe auszuführen. Stellen Sie es so ein, dass es einmal und in einem Intervall von 1 Sekunde läuft. Setzen Sie den UI-Code in das Tick-Ereignis und setzen Sie ihn dann ab.
Wenn Sie wirklich Aufgaben verwenden möchten, möchten Sie, dass die andere Aufgabe nicht im Benutzeroberflächen-Thread ausgeführt wird, sondern in einer Hintergrundbedrohung (dh nur eine normale StartNew
Aufgabe) und Verwenden Sie dann das Control.Invoke innerhalb der Aufgabe, um einen Befehl im UI-Thread auszuführen. Das Problem dabei ist, dass das zugrundeliegende Problem, eine Aufgabe zu beginnen, nur um es schlafen zu lassen, band-assistiert wird. Besser, wenn der Code nicht einmal für die volle Sekunde ausgeführt wird.
Tags und Links c# multithreading winforms sleep taskfactory