Auslösen eines Ereignisses jede Sekunde

8

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.

    
R.Gregory 02.03.2010, 15:58
quelle

7 Antworten

7

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.

%Vor%

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.)

    
G-Wiz 02.03.2010, 16:08
quelle
4

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.

    
Ray Burns 02.03.2010 16:06
quelle
1

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.

    
Randy Minder 02.03.2010 16:02
quelle
1

Verwenden Sie einen Timer wie folgt:

%Vor%

Das verstrichene Ereignis wird in einem ThreadPool-Thread behandelt, daher müssen Sie dies berücksichtigen, wenn Sie die Benutzeroberfläche vom veralteten Handler aktualisieren müssen.

    
Ed Power 03.03.2010 17:07
quelle
0

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.

    
maranas 02.03.2010 16:12
quelle
0

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:

%Vor%

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!

    
Enigmativity 16.03.2014 01:17
quelle
0

Verwenden Sie einen Timer wie folgt:

%Vor%     
M'Adil Memon 26.07.2014 00:00
quelle

Tags und Links