Frage

Derzeit habe ich eine große Anzahl von Berechnungen, C # (Methode Anrufe) in einer Warteschlange mit Wohnsitz, die sequentiell ausgeführt werden. Jede Berechnung wird einig mit hohem Latenz-Dienst verwenden (Netzwerk, Festplatte ...).

Ich wollte Mono Koroutinen verwenden die nächste Berechnung in der Berechnungs Warteschlange zu ermöglichen fortzusetzen, während eine vorherige Berechnung wird für die hohe Latenz-Service Rückkehr warten. Allerdings habe ich es vorziehen, hängt nicht von Mono Koroutinen.

Gibt es ein Design-Muster, das in reinem C # implementierbar ist, die mir ermöglichen wird, zusätzliche Berechnungen zu verarbeiten, während für hohe Latenz Dienste Rückkehr warten?

Danke

Update:

Ich brauche eine große Zahl (> 10000) von Aufgaben auszuführen, und jede Aufgabe wird mit etwas hohen Latenz Service sein. Unter Windows können Sie, dass viel Threads nicht erstellen können.

Update:

Im Grunde brauche ich ein Design-Muster, das die Vorteile emuliert (wie folgt) von Tasklets in Stackless Python ( http: // www.stackless.com/ )

  1. Sehr große Anzahl der Aufgaben
  2. Wenn eine Task blockiert die nächste Aufgabe in der Warteschlange ausführt
  3. Keine verschwendet CPU-Zyklus
  4. Minimal Kopf Umschalten zwischen Aufgaben
War es hilfreich?

Lösung

Sie können die kooperative simulieren microthreading IEnumerable verwenden. Leider wird dies nicht die Arbeit mit APIs zu blockieren, so dass Sie APIs müssen feststellen, dass Sie abfragen können, oder die Rückrufe haben, dass Sie für die Signalisierung verwenden können.

Betrachten wir eine Methode

IEnumerable Thread ()
{
    //do some stuff
    Foo ();

    //co-operatively yield
    yield null;

    //do some more stuff
    Bar ();

    //sleep 2 seconds
    yield new TimeSpan (2000);
}

Der C # Compiler auspacken dies in eine Zustandsmaschine -. Aber das Aussehen ist das ein kooperativer Microthread

Das Muster ist ganz einfach. Sie implementieren eine „Scheduler“, die eine Liste aller aktiven IEnumerators hält. Da es Zyklen durch die Liste, es „runs“ jede Verwendung Movenext (). Wenn der Wert von Movenext falsch ist, hat der Thread beendet, und der Scheduler entfernt sich aus der Liste. Wenn es wahr ist, dann greift der Planer die Current-Eigenschaft den aktuellen Zustand des Fadens zu bestimmen. Wenn es eine Zeitspanne, die Thread-Wünsche zu schlafen, und der Scheduler bewegte es auf einige Warteschlangen, die gespült zurück in die Hauptliste sein können, wenn die Schlafzeitspannen beendet haben.

Sie können die anderen Rückgabe Objekte verwenden, um andere Signalmechanismen zu implementieren. Zum Beispiel definiert eine Art von Waithandle. Wenn der Faden eine davon ergibt, kann es zu einer Warteschlange bewegt werden, bis der Handgriff signalisiert wird. Oder Sie könnten WaitAll unterstützen, indem sie eine Reihe von Wartegriffe ergeben. Sie könnten sogar Prioritäten umzusetzen.

habe ich eine einfache Implementierung dieser Scheduler in etwa 150LOC aber ich habe nicht rund um den Code noch bloggen. Es war für unsere PhyreSharp Phyreengine Wrapper (die nicht öffentlich sein wird), wo sie für die Steuerung ein paar hundert Zeichen in einem unserer Demos ziemlich gut zu funktionieren scheint. Wir liehen uns das Konzept von der Unity3D-Engine - sie einige Online-Dokumentation, die es von einem Benutzer Sicht erklären

.

Andere Tipps

Ich würde empfehlen, das Thread-Pool mehr Aufgaben aus der Warteschlange zur Ausführung auf einmal in überschaubaren Chargen eine Liste der aktiven Aufgaben verwenden, das von der Task-Queue-Feeds aus.

In diesem Szenario Ihres Hauptarbeitsthread würde zunächst N Aufgaben aus der Warteschlange in die aktiven Aufgabenliste Pop bis zum Thread-Pool versandt werden (höchstwahrscheinlich mit QueueUserWorkItem ), wobei N eine überschaubare Menge darstellt, die nicht den Thread-Pool überlasten, bog die App nach unten mit Gewinde Planung und Synchronisationskosten oder aufzusaugen verfügbare Speicher aufgrund des kombinierten E / A-Speicher-Overhead jeder Aufgabe.

Jedes Mal, wenn ein Aufgabe signalisiert den Abschluss an den Worker-Thread, können Sie es aus der aktiven Aufgaben-Liste entfernen und die nächsten von Ihrer Aufgabenwarteschlange hinzufügen ausgeführt werden.

Damit können Sie ein Roll Satz von N Aufgaben aus der Warteschlange haben. Sie können N manipulieren, um die Leistungseigenschaften zu beeinflussen und finden, was in Ihren besonderen Umständen am besten ist.

Da Sie schließlich durch Hardware-Operationen Engpass werden (Disk-I / O und Netzwerk-I / O, CPU) ich kleiner vorstellen, ist besser. Zwei Thread-Pool Aufgaben arbeiten an Disk-I / O wahrscheinlich nicht schneller ausführen als ein.

Sie können auch Flexibilität in der Größe und den Inhalt der aktiven Aufgabenliste implementieren, indem sie auf eine festgelegte Anzahl von bestimmten Art von Aufgabe zu beschränken. Wenn Sie zum Beispiel auf einer Maschine mit 4 Kernen laufen, könnten Sie feststellen, dass die leistungsfähigste Konfiguration vier CPU-gebundenen Aufgaben gleichzeitig zusammen mit einer Disk-bound Aufgabe ausgeführt wird und ein Netzwerk Aufgabe.

Wenn Sie bereits eine Aufgabe als Disk IO Aufgabe klassifiziert haben, können Sie wählen, zu warten, bis es vor dem Hinzufügen von anderer Datenträger IO-Task abgeschlossen ist, und Sie können wählen, um in der Zwischenzeit eine CPU-gebunden oder Netzwerk-gebundene Aufgabe planen .

Hope dies macht Sinn!

PS: Haben Sie Abhängigkeiten in der Größenordnung von Aufgaben

Sie sollten auf jeden Fall die Concurrency and Coordination Runtime . Einer ihrer Proben beschreibt genau das, was Sie sprechen: Sie rufen zu langer Latenz Dienstleistungen und die CCR ermöglicht effizient eine andere Aufgabe ausgeführt werden soll, während Sie warten. Es kann sehr große Anzahl von Aufgaben bewältigen, weil es nicht einen Thread für jeden zum Laichen braucht, obwohl es alle Ihre Kerne verwenden, wenn Sie danach fragen.

Ist das nicht eine herkömmliche Verwendung von Multi-Threaded-Verarbeitung?

Hier finden Sie aktuelle Muster wie Reactor hier

es schreiben Async IO möglicherweise ausreichend.

Dies kann bei der Konstruktion ohne feste Struktur zu Debug-Code zu nasy, hart führen.

Sie sollten einen Blick auf diese:

http://www.replicator.org/node/80

Dies sollte genau das tun, was Sie wollen. Es ist ein Hack, aber.

Einige weitere Informationen über die „Reaktive“ Muster (wie von einem anderen Poster erwähnt) in Bezug auf eine Implementierung in .NET; aka "Linq to Event"

http://themechanicalbride.blogspot.com /2009/07/introducing-rx-linq-to-events.html

-Oisin

In der Tat, wenn Sie einen Thread für eine Aufgabe verwenden, werden Sie das Spiel verlieren. Denken Sie darüber nach, warum Node.js große Anzahl von conections unterstützen kann. Unter Verwendung einer geringen Anzahl von Thread mit async IO !!! Async und await Funktionen können auf diese helfen.

foreach (var task in tasks)
{
    await SendAsync(task.value);
    ReadAsync(); 
}

SendAsync () und ReadAsync () gefälscht Funktionen async IO Aufruf.

Parallelität Aufgabe ist auch eine gute wählen. Aber ich bin nicht sicher, welche schneller ist. Sie können beide testen in Ihrem Fall.

Ja natürlich möglich. Sie brauchen nur einen Dispatcher Mechanismus zu bauen, die auf einem Lambda-Rückruf wird, dass Sie zur Verfügung stellen und geht in eine Warteschlange. Der gesamte Code schreibe ich in der Einheit verwendet diesen Ansatz, und ich benutze nie Koroutinen. Ich wickle Methoden, dass die Verwendung Koroutinen wie WWW Zeug einfach loswerden. In der Theorie können Koroutinen schneller sein, weil es weniger Overhead ist. Praktisch eine ziemlich triviale Aufgabe, die sie einführen neue Syntax zu einer Sprache zu tun, und darüber hinaus können Sie nicht dem Stack-Trace richtig auf einem Fehler in einer Co-Routine folgen, weil alles, was Sie sehen werden ist -> Weiter. Sie müssen dann die Möglichkeit implementieren, um die Aufgaben in der Warteschlange auf einem anderen Thread ausgeführt werden. Allerdings gibt es parallel Funktionen in der neuesten .net und Sie im Wesentlichen eine ähnliche Funktionalität zu schreiben würde. Es wäre nicht wirklich viele Zeilen Code sein.

Wenn jemand interessiert ist, würde ich den Code senden, hat es nicht auf mir.

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