Schlaf-task (System.Threading.Aufgaben)
Brauche ich zum erstellen von thread-ersetzt Foto in Windows Forms Fenster, als wartet ~1s und die Wiederherstellung des vorherigen Foto.
Dachte ich, dass der folgende code:
TaskScheduler ui = TaskScheduler.FromCurrentSynchronizationContext();
var task = Task.Factory.StartNew(() =>
{
pic.Image = Properties.Resources.NEXT;
Thread.Sleep(1000);
pic.Image = Properties.Resources.PREV;
}, CancellationToken.None, TaskCreationOptions.LongRunning, ui)
den job zu erledigen, aber leider nicht. Es friert die Haupt-UI-thread.
Das ist, weil es ist nicht garantiert, dass es nur einen thread pro Aufgabe. Ein thread kann genutzt werden für die Bearbeitung mehrerer Aufgaben.
Auch TaskCreationOptions.LongRunning option nicht helfen kann.
Wie ich es beheben kann?
- Erstellen Sie die task scheduler durch die Verwendung
FromCurrentSynchronizationContext()
, die für WinForms wird der UI-thread. Also deine Aufgabe, schließlich läuft auf dem UI-thread, die Sie gehen dann zum schlafen gelegt. Don ' T setzen Sie den UI-thread schlafen. Je. - Ihre code-updates der UI direkt, so muss es auf dem UI-thread. Ihr code schläft, also es läuft nicht auf dem UI-thread. Fazit: Dein code ist fehlerhaft. Fixieren Sie es durch das entfernen einer der beiden in Konflikt stehenden Anforderungen.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Thread.Schlaf ist ein synchrone Verzögerung. Wenn Sie möchten, eine asynchronen Verzögerung dann verwenden Aufgabe.Delay.
In C# 5, die ist momentan in der beta-Version, Sie können einfach sagen
in einer asynchronen Methode, und die Methode wird automatisch abholen, wo Sie aufgehört haben.
Wenn Sie sich nicht mit C# 5 dann kannst du auf "manuell" stellen, was auch immer code, den Sie wollen, um die Fortsetzung der Verzögerung selbst.
Wenn Sie an einem neuen Aufgabenplaner, der ist aus der aktuellen Synchronisierung von Rahmen, die Sie tatsächlich sagen, die Aufgabe auszuführen, die auf dem UI-thread. Sie wirklich wollen, zu tun, so können Sie aktualisieren Sie die UI-Komponente, aber Sie wollen nicht schlafen in diesem thread, da es blockiert.
Dies ist ein gutes Beispiel, wenn
.ContinueWith
ist ideal:BEARBEITEN (Entfernt einige Sachen Hinzugefügt und diese):
Was passiert, ist, dass wir die Blockierung der UI-thread für nur genug Zeit, Sie zu aktualisieren
pic.Image
. Durch die Angabe derTaskScheduler
, du erzählst es, was thread zum ausführen der Aufgabe auf. Es ist wichtig zu wissen, dass die Beziehung zwischen Tasks und Threads, die nicht 1:1. In der Tat können Sie über 1000 ausgeführten Aufgaben auf relativ wenige threads, 10 oder sogar weniger, es hängt alles von der Menge der Arbeit, die jede Aufgabe hat. Nicht davon ausgehen, jede Aufgabe, die Sie erstellen, werden in einem separaten thread ausgeführt. Die CLR macht einen guten job balancing performance automatisch für Sie.Nun, Sie müssen nicht auf die Standard -
TaskScheduler
, wie Sie gesehen haben. Wenn Sie übergeben die UITaskScheduler
, das istTaskScheduler.FromCurrentSynchronizationContext()
verwendet es den UI-thread statt dem thread-pool, alsTaskScheduler.Default
tut.Dieses im Verstand halten, lassen Sie uns überprüfen Sie den code erneut:
Hier, wir erstellen und starten einer Aufgabe ausgeführt wird, auf der UI thread, dass ein update der
Image
Eigenschaft vonpic
mit Ihrer Ressource. Während es dies tut, die UI wird nicht reagiert. Glücklicherweise ist das wahrscheinlich ein sehr schnelle Bedienung, und der Benutzer nicht einmal bemerken.Mit diesem code, wir fordern die
ContinueWith
Methode. Es tut genau, was es klingt wie. Es gibt ein neuesTask
- Objekt, das ausgeführt wird, der lambda-parameter, wenn es läuft. Es wird gestartet, wenn die Aufgabe entweder beendet, fehlgeschlagen oder wurde abgebrochen. Sie können Steuern, wenn es ausgeführt wird, indem inTaskContinuationOptions
. Allerdings werden wir auch die übergabe einer anderen task scheduler, wie wir es getan haben, bevor. Dies ist die Standard-task-scheduler zum ausführen einer Aufgabe auf einem threadpool-thread, also KEINE Blockierung der Benutzeroberfläche. Diese Aufgabe könnte stundenlang laufen und Ihre Benutzeroberfläche bleiben reaktionsschnell Weg (lassen Sie es nicht), weil es einen separaten thread aus der UI-thread, der Sie interagieren.Haben wir auch als
ContinueWith
auf die Aufgaben, die wir festgelegt haben zu laufen auf der Standard-task-scheduler. Dies ist die Aufgabe, die aktualisieren das Bild auf dem UI-thread wieder, da wir bestanden haben, die gleiche UI task-scheduler, um die Ausführung der Aufgabe. Einmal den threadpool ein task beendet wurde, wird diese auf dem UI-thread blockiert es für eine sehr kurze Zeit, während das Bild aktualisiert wird.TableLayoutPanel
mitPictureBox
es in der it (ich will nicht zu haben, so viele Timer wiePictureBox
es). Ich legte diese Aufgabe den code im OnClick-event-handler, da ich tauschen wollen Bilder für 1sec. nach einem Klick auf Bild geklickt.TaskScheduler
(.Default
eine). Was bedeutet es? Wechselnden Kontext-zu-threadpool-thread-Kontext? So stoppen wir rest des threads? Das ist nicht klar für mich.pic.Image = Properties.Resources.XYZ
ist schnell in Betrieb (und ist es schnell genug).Sollten Sie mit einem
Timer
zum durchführen einer UI-Aufgabe an einem gewissen Punkt in der Zukunft. Einfach einmal ausführen, und mit einer 1-Sekunden-Intervall. Setzen Sie den UI-code im tick-Ereignis und legen Sie es anschließend aus.Wenn Sie wirklich wollte tasks verwenden, würden Sie wollen, um die andere Aufgabe nicht in der UI-thread, sondern in einen hintergrund der Bedrohung (D. H. nur eine regelmäßige
StartNew
Aufgabe) und verwenden Sie dann die Steuerung.Aufrufen innerhalb der Aufgabe zum ausführen eines Befehls auf dem UI-thread. Das problem hier ist, dass' band-aid-ing die zugrunde liegende problem von starten einer Aufgabe, nur um es sleep. Besser, nur haben Sie den code auch nicht ausführen, in den ersten Platz für die volle Sekunde.