it-swarm.com.de

Kann jemand in einfachen Worten erklären, was das Disruptormuster ist?

Ich würde gerne, wenn Sie mir auf einfache Weise erklären könnten, wie das Disruptor-Klappern funktioniert. Dieses Konzept war mir bekanntlich schwer zu fassen.

Vielleicht könnte ich es mit Ihrer Hilfe verstehen.

35
chrisapotek

Die Fowler Article Anbieter bieten eine gute Grundierung, und diese Erklärung:

Auf einer groben Ebene können Sie sich einen Disruptor als ein Multicast-Diagramm von Warteschlangen vorstellen, auf dem Produzenten Objekte ablegen, die über separate nachgeschaltete Warteschlangen zum parallelen Verbrauch an alle Verbraucher gesendet werden. Wenn Sie hineinschauen, sehen Sie, dass dieses Netzwerk von Warteschlangen wirklich eine einzelne Datenstruktur ist - ein Ringpuffer.

Jeder Produzent und Konsument hat einen Sequenzzähler, der angibt, an welchem ​​Steckplatz im Puffer er gerade arbeitet. Jeder Produzent/Verbraucher schreibt seinen eigenen Sequenzzähler, kann jedoch die Sequenzzähler der anderen lesen. Auf diese Weise kann der Hersteller die Zähler der Verbraucher lesen, um sicherzustellen, dass der Steckplatz, in den er schreiben möchte, ohne Sperren an den Zählern verfügbar ist. Ebenso kann ein Verbraucher sicherstellen, dass er Nachrichten erst verarbeitet, wenn ein anderer Verbraucher damit fertig ist, indem er die Zähler überwacht.

enter image description here

Ein konventionellerer Ansatz könnte eine Producer Queue und eine Consumer Queue verwenden, die jeweils Sperren als Parallelitätsmechanismen verwenden. In der Praxis passiert bei Produzenten- und Konsumentenwarteschlangen, dass die Warteschlangen die meiste Zeit entweder vollständig leer oder vollständig gefüllt sind, was zu Sperrenkonflikten und verschwendeten Taktzyklen führt. Der Disruptor lindert dies teilweise, indem alle Hersteller und Verbraucher denselben Warteschlangenmechanismus verwenden und sich durch Beobachten der Sequenzzähler koordinieren, anstatt Sperrmechanismen zu verwenden.

32
Robert Harvey

Aus diesem Artikel über CoralQueue :

Das Disruptormuster ist eine Stapelwarteschlange, die durch ein kreisförmiges Array (d. H. Den Ringpuffer) gesichert ist, das mit vorab zugewiesenen Übertragungsobjekten gefüllt ist und Speicherbarrieren verwendet, um Produzenten und Konsumenten durch Sequenzen zu synchronisieren.

Produzenten und Konsumenten treten also nicht innerhalb des kreisförmigen Arrays aufeinander, indem sie ihre entsprechenden Sequenzen überprüfen . Und um ihre Sequenzen hin und her zu kommunizieren, verwenden sie Speicherbarrieren anstelle von Sperren. Dies ist die schnellste Art der Kommunikation ohne Sperren.

Glücklicherweise müssen Sie nicht auf die internen Details des Disruptormusters zurückgreifen, um es zu verwenden. Neben der LMAX-Implementierung gibt es CoralQueue , entwickelt von Coral Blocks, mit dem ich verbunden bin. Einige Leute finden es einfacher, ein Konzept durch Lesen von Code zu verstehen. Im Folgenden finden Sie ein einfaches Beispiel für einen einzelnen Hersteller, der Nachrichten an einen einzelnen Verbraucher sendet. Sie können auch diese Frage für ein Demultiplexer-Beispiel (ein Hersteller für viele Verbraucher) überprüfen.

package com.coralblocks.coralqueue.sample.queue;

import com.coralblocks.coralqueue.AtomicQueue;
import com.coralblocks.coralqueue.Queue;
import com.coralblocks.coralqueue.util.Builder;

public class Basics {

    public static void main(String[] args) {

        final Queue<StringBuilder> queue = new AtomicQueue<StringBuilder>(1024, new Builder<StringBuilder>() {
            @Override
            public StringBuilder newInstance() {
                return new StringBuilder(1024);
            }
        });

        Thread producer = new Thread(new Runnable() {

            private final StringBuilder getStringBuilder() {
                StringBuilder sb;
                while((sb = queue.nextToDispatch()) == null) {
                    // queue can be full if the size of the queue
                    // is small and/or the consumer is too slow

                    // busy spin (you can also use a wait strategy instead)
                }
                return sb;
            }

            @Override
            public void run() {

                StringBuilder sb;

                while(true) { // the main loop of the thread

                    // (...) do whatever you have to do here...

                    // and whenever you want to send a message to
                    // the other thread you can just do:
                    sb = getStringBuilder();
                    sb.setLength(0);
                    sb.append("Hello!");
                    queue.flush();

                    // you can also send in batches to increase throughput:
                    sb = getStringBuilder();
                    sb.setLength(0);
                    sb.append("Hi!");

                    sb = getStringBuilder();
                    sb.setLength(0);
                    sb.append("Hi again!");

                    queue.flush(); // dispatch the two messages above...
                }
            }
        }, "Producer");

        Thread consumer = new Thread(new Runnable() {

            @Override
            public void run() {

                while (true) { // the main loop of the thread

                    // (...) do whatever you have to do here...

                    // and whenever you want to check if the producer
                    // has sent a message you just do:

                    long avail;
                    while((avail = queue.availableToPoll()) == 0) {
                        // queue can be empty!
                        // busy spin (you can also use a wait strategy instead)
                    }

                    for(int i = 0; i < avail; i++) {
                        StringBuilder sb = queue.poll();
                        // (...) do whatever you want to do with the data
                        // just don't call toString() to create garbage...
                        // copy byte-by-byte instead...
                    }
                    queue.donePolling();
                }
            }
        }, "Consumer");

        consumer.start();
        producer.start();
    }
}

Haftungsausschluss: Ich bin einer der Entwickler von CoralQueue.

9
rdalmeida