Wie kann ich die asynchronen Pipelines, aus denen das Combine-Framework besteht, synchron (seriell) ausrichten?
Angenommen, ich habe 50 URLs, von denen ich die entsprechenden Ressourcen herunterladen möchte, und nehmen wir an, ich möchte dies einzeln tun. Ich weiß, wie man das mit Operation / OperationQueue macht, z. B. mit einer Operation-Unterklasse, die sich erst nach Abschluss des Downloads für beendet erklärt. Wie würde ich mit Combine dasselbe machen?
Im Moment fällt mir nur ein, eine globale Liste der verbleibenden URLs zu führen und eine zu entfernen, diese eine Pipeline für einen Download einzurichten, den Download durchzuführen und in sink
der Pipeline zu wiederholen. Das scheint nicht sehr kombinationsartig zu sein.
Ich habe versucht, ein Array der URLs zu erstellen und es einem Array von Publishern zuzuordnen. Ich weiß, dass ich einen Publisher "produzieren" und veranlassen kann, dass er in der Pipeline mit veröffentlicht wird flatMap
. Aber dann lade ich immer noch alle gleichzeitig herunter. Es gibt keine kombinierte Möglichkeit, das Array kontrolliert zu durchlaufen - oder gibt es eine?
(Ich habe mir auch vorgestellt, etwas mit Future zu machen, aber ich wurde hoffnungslos verwirrt. Ich bin an diese Denkweise nicht gewöhnt.)
append
ist genau das, wonach ich gesucht habe. - Ihr Code kann erheblich verschärft werden. Insbesondere ist es nicht erforderlich, vorzeitig zurückzukehrencount == 1
, wenn dies der Fall ist , da in diesem FalldropFirst
leer ist und wir einfach keine Schleife ausführen. Und es besteht keine Notwendigkeit, dieoutput
Variable zu pflegen , da wirreduce
stattdessen verwenden könnenfor...in
. Siehe meine Antwort für eine engere Darstellung.Sie können einen benutzerdefinierten Abonnenten erstellen, in dem wiederkehrende Abonnenten empfangen werden.Demand.max (1). In diesem Fall fordert der Teilnehmer den nächsten Wert erst an, wenn er einen erhalten hat. Das Beispiel ist für Int.publisher, aber eine zufällige Verzögerung der Karte ahmt den Netzwerkverkehr nach :-)
Spielplatzdruck ...
UPDATE habe ich endlich gefunden
.flatMap(maxPublishers: )
, was mich zwingt, dieses interessante Thema mit einem etwas anderen Ansatz zu aktualisieren. Bitte beachten Sie, dass ich die globale Warteschlange für die Planung verwende, nicht nur eine zufällige Verzögerung, nur um sicherzugehen, dass das Empfangen eines serialisierten Streams kein "zufälliges" oder "glückliches" Verhalten ist :-)druckt
Basierend auf hier geschrieben
.serialize ()?
Die von Clay Ellis definierte akzeptierte Antwort könnte durch ersetzt werden
.publisher.flatMap (maxPublishers: .max (1)) {$ 0}
während "unserialzed" Version muss verwendet werden
.publisher.flatMap {$ 0}
"Beispiel aus der realen Welt"
druckt
Scheint mir auch in anderen Szenarien sehr nützlich zu sein. Versuchen Sie, den Standardwert von maxPublishers im nächsten Snippet zu verwenden und vergleichen Sie die Ergebnisse :-)
quelle
maxPublishers
Parameter können wir den Gegendruck erhöhen. Dies hängt mit dem zusammen, was ich in meiner Frage gesagt habe: "Ich weiß, dass ich einen Publisher" produzieren "und veranlassen kann, dass er mit flatMap in der Pipeline veröffentlicht wird. Aber dann lade ich immer noch alle gleichzeitig herunter." Nun, mit demmaxPublishers
Parameter sind sie nicht gleichzeitig.In allen anderen reaktiven Frameworks ist dies wirklich einfach. Sie verwenden nur
concat
, um die Ergebnisse in einem Schritt zu verketten und zu reduzieren, und dann können Siereduce
die Ergebnisse in ein endgültiges Array umwandeln. Apple macht dies schwierig, daPublisher.Concatenate
es keine Überlastung gibt, die eine Reihe von Publishern akzeptiert. Es gibt eine ähnliche Verrücktheit mitPublisher.Merge
. Ich habe das Gefühl, dass dies damit zu tun hat, dass sie verschachtelte generische Publisher zurückgeben, anstatt nur einen einzelnen generischen Typ wie rx Observable zurückzugeben. Ich denke, Sie können einfach Verketten anrufenin einer Schleife und reduzieren Sie dann die verketteten Ergebnisse in ein einziges Array, aber ich hoffe wirklich, dass sie dieses Problem in der nächsten Version beheben. Es besteht sicherlich die Notwendigkeit, mehr als 2 Verlage zusammenzufassen und mehr als 4 Verlage zusammenzuführen (und die Überlastungen für diese beiden Betreiber sind nicht einmal konsistent, was nur seltsam ist).BEARBEITEN:
Ich bin darauf zurückgekommen und habe festgestellt, dass Sie tatsächlich eine beliebige Anzahl von Verlagen zusammenstellen können, die nacheinander emittieren. Ich habe keine Ahnung, warum es keine Funktion gibt
ConcatenateMany
, die dies für Sie erledigt, aber es sieht so aus, als wäre es nicht so schwer, selbst einen zu schreiben, solange Sie bereit sind, einen vom Typ gelöschten Verlag zu verwenden. Dieses Beispiel zeigt, dass Merge in zeitlicher Reihenfolge ausgegeben wird, während Concat in der Reihenfolge der Kombination ausgegeben wird:quelle
concat
serialisieren (in den anderen reaktiven Frameworks)?.append
ein Operator ist, der a erstelltPublisher.Concatenate
.Aus der ursprünglichen Frage:
Hier ist ein Spielzeugbeispiel für das eigentliche Problem:
Dies gibt die ganzen Zahlen von 1 bis 10 in zufälliger Reihenfolge aus, die zu zufälligen Zeiten eintreffen. Das Ziel ist es, etwas damit zu tun,
collection
das dazu führt, dass die ganzen Zahlen der Reihe nach von 1 bis 10 ausgegeben werden.Jetzt werden wir nur eines ändern: in der Reihe
Wir fügen den
maxPublishers
Parameter hinzu:Presto, wir jetzt tun emit die ganzen Zahlen von 1 bis 10, um mit zufälligen Abständen zwischen ihnen.
Wenden wir dies auf das ursprüngliche Problem an. Um dies zu demonstrieren, benötige ich eine ziemlich langsame Internetverbindung und eine ziemlich große Ressource zum Herunterladen. Zuerst mache ich es mit gewöhnlichen
.flatMap
:Das Ergebnis ist
Dies zeigt, dass wir die drei Downloads gleichzeitig durchführen. Okay, jetzt ändere dich
zu
Das Ergebnis ist jetzt:
Wir laden jetzt seriell herunter, was das ursprünglich zu lösende Problem ist.
anhängen
In Übereinstimmung mit dem Prinzip von TIMTOWTDI können wir stattdessen die Herausgeber verketten,
append
um sie zu serialisieren:Das Ergebnis ist ein Herausgeber, der die verzögerten Herausgeber in der ursprünglichen Sammlung serialisiert. Lassen Sie es uns beweisen, indem Sie es abonnieren:
Sicher genug, die ganzen Zahlen kommen jetzt in der richtigen Reihenfolge an (mit zufälligen Intervallen dazwischen).
Wir können die Erstellung
pub
einer Sammlung von Verlagen mit einer Erweiterung der Sammlung zusammenfassen, wie von Clay Ellis vorgeschlagen:quelle
Hier ist ein einseitiger Spielplatzcode, der den möglichen Ansatz darstellt. Die Hauptidee besteht darin, asynchrone API-Aufrufe in eine
Future
Herausgeberkette umzuwandeln und so eine serielle Pipeline zu erstellen .Eingabe: Bereich von int von 1 bis 10, der asynchron in der Hintergrundwarteschlange in Zeichenfolgen konvertiert wird
Demo des direkten Aufrufs der asynchronen API:
Ausgabe:
Demo der Mähdrescher-Pipeline:
Ausgabe:
Code:
quelle
Verwenden Sie
flatMap(maxPublishers:transform:)
mit.max(1)
zWo
und
Das führte zu:
Aber wir sollten erkennen, dass Sie einen großen Performance-Hit erzielen, wenn Sie sie so nacheinander ausführen. Wenn ich es zum Beispiel auf 6 gleichzeitig stoße, ist es mehr als doppelt so schnell:
Persönlich würde ich empfehlen, nur nacheinander herunterzuladen, wenn Sie dies unbedingt müssen (was beim Herunterladen einer Reihe von Bildern / Dateien mit ziemlicher Sicherheit nicht der Fall ist). Ja, das gleichzeitige Ausführen von Anforderungen kann dazu führen, dass sie nicht in einer bestimmten Reihenfolge abgeschlossen werden. Wir verwenden jedoch nur eine auftragsunabhängige Struktur (z. B. ein Wörterbuch anstelle eines einfachen Arrays), aber die Leistungssteigerungen sind so bedeutend, dass es sich im Allgemeinen lohnt.
Wenn Sie sie jedoch nacheinander herunterladen möchten, kann der
maxPublishers
Parameter dies erreichen.quelle
maxPublishers
Option gefunden haben. Und ich hätte nicht über "Don't Do Serial" nachgedacht, wenn ich bemerkt hätte, dass Sie es waren (da ich weiß, dass Sie die Vor- und Nachteile von Serial vs Concurrent vollständig verstehen). Ich sah buchstäblich nur "Ich möchte jeweils eine Datei herunterladen", ich war kürzlich auf diemaxPublishers
Option für etwas anderes gestoßen, das ich tat (nämlich eine moderne Lösung für diese Frage bereitzustellen ), und ich dachte, ich würde die Kombinationslösung I teilen hatte sich ausgedacht. Ich wollte nicht so abgeleitet sein.