Die Implementierung ‚nur einer von‘ und ‚nicht parallel‘ Semantik mit der Task Parallel Library

StackOverflow https://stackoverflow.com/questions/3613812

  •  26-09-2019
  •  | 
  •  

Frage

Was ist der beste Ansatz für die Umsetzung von Aufgaben mit einem Schlüssel, der wie folgt funktionieren würde: -

Option 1) Nur eine dieser Schlüssel immer anhängig ist. Kann verwendet werden, zum Beispiel von ASP.NET MVC ganz gleich ein einzelnen machen für ein Miniaturbild in der Warteschlange einzureihen, wie oft das Bild URL getroffen wird. Nur ein Läufe, alle anderen Anfragen warten, dass man vollständig.

Option 2) Alle Einzelteile mit dem gleichen Schlüssel nacheinander ausgeführt werden müssen. Kann beispielsweise verwendet werden, um sicherzustellen, dass Operationen, die eine Datei von einem Sicherungsspeicher in einem lokalen Cache holen nicht alle versuchen, die Datei in die Cache zur gleichen Zeit zu bekommen. Option 1 ist ein Spezialfall davon, wo nachfolgende Aktionen mit dem gleichen Schlüssel einfach verworfen werden (in der Regel speichert nur eine Datei-exists-Check).

Ich habe einen bestehenden Workqueue, dass Griffe diesen beiden Fällen (sowie Wohnung Zustand, Thread Einstellungen und maximalen Grad der Parallelität). TPL scheint die beste Lösung zu sein, dies für den Ersatz und wird verbesserte Stornierungsmöglichkeiten bringen.

Verschachtelte Aufgaben mit Fortsetzungen schauen hoffnungsvoll, aber ein Wörterbuch zur Zeit queue'd Aufgaben beibehalten wird bald chaotisch zwischen der Taskfactory und den Taskscheduler-Klassen. Vererben von Aufgaben problematisch ist auch da weder noch Taskfactory Taskscheduler generisch sind auf Aufgabe.

Die meisten Task Parallel Beispiele gehen davon aus, dass die Reihe von Aufgaben vor der Zeit bekannt ist. In diesem Fall werden neue Aufgaben die ganze Zeit und Bedarf hinzugefügt entweder verworfen oder auf bestehende Aufgaben auf den Betrieb abhängig angekettet angefordert werden und der Schlüssel übergeben.

Hat jemand implementiert etwas ähnlich wie diese mit TPL und wenn ja, welche Ansatz haben Sie nehmen in Ihrer Aufgabe, Taskscheduler und Taskfactory Klassen?

War es hilfreich?

Lösung

Vielleicht eine Art und Weise, dass ich mir vorstellen kann ist

  1. eine Wrapper-Klasse erstellen - sagen Keyprocessor Elemente für einen Schlüssel in die Warteschlange einzureihen.
  2. KeyProcessor.Run () -Methode wird jeglicher Warteschlangen Semantik der Lage sein, die Sie benötigen für. Im Grunde wäre es für alle anstehenden Arbeiten für die interne Warteschlange suchen und dann der Reihe nach tun es halten.
  3. Pflegen das Wörterbuch von Keyprocessor Objekte.
  4. Für jede neue Aufgabe, aktivieren Sie im Wörterbuch für den gleichen Schlüssel. Wenn nicht existiert dann hinzufügen. Warteschlange die Aufgabe auf sich. Wenn es nicht läuft es dann plant mit TPL mit Run-Methode als Aktion.
  5. Verwenden Sie ContinueWith Zeitplan Maintainer Aufgabe - zum Beispiel, wann immer Aufgabe KeyProcessor.Run Ausführung abgeschlossen ist, kann die Fortsetzung Aufgaben prüfen, ob es noch weitere Aufgaben für den gleichen Schlüssel geplant worden (da es abgeschlossen ist) und starten Sie es erneut oder entfernen von Wörterbuch.

Alle oben heikel gewesen von Thread Sync-Punkt würde nicht für einige interessante Sammlungen in System.Collections.Concurrent Namespace. Dies würde die obige Logik viel einfacher. Zum Beispiel ConcurrentDictionary.GetOrAdd ermöglicht nachzuschlagen und / oder Add das Keyprocessor Objekt in thread-sicher.

Andere Tipps

Dieses Problem ist ähnlich wie ein löste ich in ReactiveXaml , obwohl Mine auch frühere Anfragen memoized. Werfen Sie einen Blick auf den Code für QueuedAsyncMRUCache (und seine Blog-Eintrag ) - dieser Code kombiniert die TPL mit dem Reactive Extensions diese Art der Sache zu erledigen, aber es macht die wichtige Garantie, dass die zweite Anforderung für den gleichen Schlüssel auf der ersten in-Flight-Anfrage blockiert statt Ausgabe eines anderen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top