Ich habe eine Anwendung, die jede Sekunde einen Website-Feed prüfen muss.
Manchmal ist die Anfrage an den Server länger als eine Sekunde. In diesem Fall muss die Anwendung warten, bis die erste Anforderung abgeschlossen ist, und dann sofort eine neue Anforderung starten. Wie kann ich das umsetzen?
Außerdem sollte die Anfrage die GUI nicht einfrieren.
Ich würde eine einfache Variante des Erzeuger-Verbraucher-Musters verwenden. Sie hätten zwei Theads, einen Producer und einen Consumer, die sich eine Integer-Variable teilen. Der Produzent würde eine System.Threading.Timer
haben, die jede Sekunde feuert, zu welcher Zeit es Interlocked.Increment
die Variable und den Verbraucher anrufen würde. Die Verbraucherlogik überprüft wiederholt den Vorschub und Interlocked.Decrement
den Zähler, während der Zähler größer als Null ist. Die Verbraucherlogik wäre durch ein Monitor.TryEnter
geschützt, das die Wiedereingliederung handhaben würde. Hier ist Beispielcode.
Verwendung:
%Vor% Eine gute Quelle für .NET Threading (neben den MSDN-Bibliotheks-Sachen) ist Jon Skeets Dokumentation, die folgendes enthält: Beispiel für Producer-Consumer unter "More Monitor
methods".
Übrigens dreht sich ein echtes Producer-Consumer-Muster um eine Sammlung von Arbeitsdaten, wobei ein oder mehrere Threads Arbeit erzeugen, indem sie Daten zu dieser Sammlung hinzufügen, während ein oder mehrere andere Threads Consumer arbeiten, indem sie Daten aus dieser Sammlung entfernen. In unserer obigen Variation sind die "Arbeitsdaten" lediglich eine Zählung der Anzahl, wie oft wir den Vorschub sofort überprüfen müssen.
(Eine andere Möglichkeit, dies zu tun, statt den Timer Callback Consume zu verwenden, besteht darin, dass der Timer-Callback eine Monitor
sperrt und pulst, die Consume wartet. In diesem Fall hat Consume eine Endlosschleife wie while(true)
, die Sie einmal in einem eigenen Thread starten, daher ist es nicht nötig, die Reentrancy mit dem Aufruf von Monitor.TryEnter
zu unterstützen.)
Ich würde geneigt sein, einen separaten Thread wie folgt zu verwenden:
%Vor% Der Dispatcher.Invoke
wechselt zum UI-Thread für das tatsächliche UI-Update. Dies implementiert Producer-Consumer sehr effizient.
Der thread.IsBackground = true
bewirkt, dass der Thread endet, wenn Ihre Anwendung beendet wird. Wenn Sie möchten, dass es früher stoppt, setzen Sie einen "Stop" -Wert auf "wahr". Der "Stop" -Wert im obigen Code wird als bool-Eigenschaft der Klasse angenommen, aber es könnte alles sein - sogar eine lokale Variable.
Ein Timer-Objekt könnte den Trick für Sie tun. Sie können festlegen, dass jede Sekunde ausgelöst wird. Der Code, der beim Timer-Feuern ausgeführt wird, deaktiviert zuerst den Timer, macht es und aktiviert den Timer erneut. Wenn der Timer deaktiviert wird, wird er nicht erneut ausgelöst, bis die Verarbeitung abgeschlossen ist.
Sie könnten versuchen, eine Hauptanwendung zu erstellen, die die GUI enthält, die Sie nicht einfrieren möchten. es würde einen Thread mit einer Schleife starten, die nach einer bestimmten Zeit iterieren würde. Wenn der Zeitgeber die festgelegte Zeit erreicht / überschreitet, starten Sie einen anderen Thread für die Anforderung. Überprüfen Sie vor dem Start, ob bereits ein Thread existiert. Wenn nicht, dann blockiere die Ausführung, bis der Anfrage-Thread fertig ist. z.B.:
%Vor%Hinweis: Mach es nicht jede Sekunde. Wie andere Poster gesagt haben, ist es ein wenig respektlos gegenüber den Seitenbesitzern. Sie riskieren, von den Website-Inhabern den Zugriff auf den Feed verweigert zu bekommen.
Ich denke, dass es am einfachsten ist, das Microsoft Reactive Framework (Rx) zu verwenden.
Also, vorausgesetzt, ich habe eine Funktion, die den Website-Feed aufruft und ein Response
-Objekt wie folgt zurückgibt:
Dann kann ich das tun, um alles zu verkabeln:
%Vor%% code_de% wird für einen Hintergrundthread aufgerufen und checkWebsiteFeed
wird im UI-Thread ausgeführt. Super einfach!
Tags und Links wpf .net c# multithreading