2012-11-28 10 views
18

Ich bin auf der Suche nach einer TPL-Datenflussblocklösung, die mehr als ein einzelnes Element enthalten kann, das mit mehreren Zielblöcken verknüpft werden kann, aber ein Element nur an einen bestimmten Zielblock weiterleiten kann, der ein Filter/Prädikat übergibt . Zu keinem Zeitpunkt sollte ein Gegenstand gleichzeitig an mehrere Zielblöcke geliefert werden, immer nur an denjenigen, der dem Filter entspricht, oder der Gegenstand kann verworfen werden. Ich mag BroadCastBlock nicht, weil, wenn ich es richtig verstehe, es keine Lieferung garantiert (oder?) Und die Filterung auf der Zielblockseite erfolgt, was bedeutet, dass BroadCastBlock im Wesentlichen Kopien jedes Elements an alle LinkedTo Zielblöcke sendet. Es kann auch nicht mehr als einen Gegenstand zu jeder Zeit halten, wenn ich es richtig verstehe. Ich möchte Post/Async nicht verwenden, sondern eine LinkTo-Kette beibehalten.TPL Dataflow, wie werden Elemente nur an einen bestimmten Zielblock unter vielen verknüpften Zielblöcken weitergeleitet?

Gibt es einen Weg um einen vollständigen benutzerdefinierten Datenflussblock? Oder verstehe ich nicht, wie BroadCastBlock funktioniert? Leider gibt es wirklich nicht viel Dokumentation, die ins Detail geht und Use Cases behandelt. Irgendwelche Ideen werden sehr geschätzt.

Antwort

22

Wenn ich Sie richtig verstehe, was Sie wollen, könnte durch eine einfache BufferBlock, die mit all Ihren Ziel-Blöcke mit Prädikaten verknüpft werden würde erreicht werden. Sie würden es auch (unbedingt) mit einer NullTarget block verknüpfen, um Artikel zu verwerfen, die nicht übereinstimmen.

Etwas wie:

var forwarder = new BufferBlock<SomeType>(); 
forwarder.LinkTo(target1, item => matchesTarget1(item)); 
forwarder.LinkTo(target2, item => matchesTarget2(item)); 
forwarder.LinkTo(DataflowBlock.NullTarget<SomeType>()); 

Auf diese Weise wird jedes Element auf das erste Ziel gesendet werden, die übereinstimmt, wenn es irgendwelche gibt.

BroadcastBlock kann nützlich sein, wenn Sie jedes Objekt an mehrere Ziele senden möchten oder wenn Sie Elemente verwerfen möchten, wenn das Ziel nicht schnell genug ist.

Mit BroadcastBlock können Elemente gelöscht werden, wenn kein Block sie akzeptiert (obwohl sie später möglicherweise akzeptiert werden). Aber wenn die Zielblöcke nicht BoundedCapacity gesetzt sind, können Sie sicher sein, dass sie alle Elemente erhalten, die sie nicht ablehnen (z. B. mithilfe des Prädikats in LinkTo()).

+0

Wie funktioniert das technisch? Wird jedes Ziel versucht, bis es eine Übereinstimmung gibt, und wenn es nicht seinen Speicher verstopft, es sei denn, es wird vom Nullzielblock gelöscht? Und ist die Reihenfolge, von welcher Zielblock ich linkTo zunächst dann dann weiter ... wichtig? –

+3

Ja, jedes Ziel wird der Reihe nach ausprobiert. Wenn kein Ziel übereinstimmt, bleibt das Objekt im Pufferblock. Und in diesem Fall ist das Verstopfen der Speicher keine große Sorge, verstopfen die Pipeline ist. Mit anderen Worten, es würde bedeuten, dass kein anderer Gegenstand von diesem Block gesendet wird, bis der problematische von irgendeinem Ziel akzeptiert wird. Deshalb ist der 'NullTarget'-Block notwendig. Und ja, die Reihenfolge ist wichtig, deshalb können Sie auch [angeben, ob Sie jedes Ziel an die Liste anhängen oder voranzustellen] (http://msdn.microsoft.com/en-us/library/system.threading.tasks .dataflow.dataflowlinkoptions.append.aspx). – svick

+0

Sie sind wirklich der Typ, um zu TDF zu gehen. Genial. Danke vielmals. Nutzen Sie ausgiebig den TPL-Datenfluss oder warum das tiefe Wissen (unter anderem) dieser Bibliothek? Sie haben bereits erwähnt, dass Sie nicht mit dem MS Concurrency-Team verbunden sind. –

6

Ich habe die akzeptierte Antwort als inkorrekt gefunden. Das NullTarget sollte mit seinem Prädikat verbunden sein, das die Negation Ihrer Konsumenten ist. Andernfalls könnten Sie Nachrichten löschen, die Sie konsumieren wollten.

var forwarder = new BufferBlock<SomeType>(); 
forwarder.LinkTo(target1, item => matchesTarget1(item)); 
forwarder.LinkTo(target2, item => matchesTarget2(item)); 
forwarder.LinkTo(DataflowBlock.NullTarget<SomeType>(), item => !matchesTarget1(item) && !matchesTarget2(item)); 
+0

Könnten Sie bitte näher erläutern, wie die Nachrichten fallen? Der Filter wird nacheinander angewendet. Wenn die Verknüpfung in der richtigen Reihenfolge erfolgt, gibt es keine Möglichkeit, eine gültige Nachricht zu löschen, richtig? – VMAtm

+0

@VMAtm Also schließlich, funktioniert das Verknüpfen der Reihenfolge nach Sequenz? Ich will nur sicher gehen .. –

+0

@ b.ben Ja, das funktioniert so – VMAtm

Verwandte Themen