Qualcuno può spiegare in termini semplici qual è il modello del disgregatore?


Risposte:


33

L' articolo Fowler offre un buon primer e questa spiegazione:

A un livello rozzo puoi pensare a un Disruptor come un grafico multicast di code in cui i produttori inseriscono oggetti che vengono inviati a tutti i consumatori per il consumo parallelo attraverso code a valle separate. Quando guardi dentro, vedi che questa rete di code è in realtà una singola struttura di dati - un buffer ad anello.

Ogni produttore e consumatore ha un contatore di sequenze per indicare su quale slot nel buffer sta attualmente lavorando. Ogni produttore / consumatore scrive il proprio contatore di sequenze ma può leggere i contatori di sequenze degli altri. In questo modo il produttore può leggere i contatori dei consumatori per assicurarsi che lo slot in cui desidera scrivere sia disponibile senza alcun blocco sui contatori. Allo stesso modo un consumatore può assicurarsi che elabori i messaggi solo quando un altro consumatore ha finito con esso guardando i contatori.

inserisci qui la descrizione dell'immagine

Un approccio più convenzionale potrebbe utilizzare una coda di produzione e una coda di consumo, ciascuna delle quali utilizza blocchi come meccanismi di concorrenza. In pratica, ciò che accade con le code dei produttori e dei consumatori è che le code sono completamente vuote o completamente piene per la maggior parte del tempo, causando conflitti di blocco e cicli di clock sprecati. Il disgregatore allevia questo, in parte, facendo in modo che tutti i produttori e i consumatori utilizzino lo stesso meccanismo di coda, coordinandosi tra loro osservando i contatori delle sequenze anziché utilizzare i meccanismi di blocco.


9

Da questo articolo su CoralQueue :

Il modello di disgregatore è una coda di batch supportata da un array circolare (ovvero il buffer dell'anello) riempito con oggetti di trasferimento pre-allocati che utilizza barriere di memoria per sincronizzare produttori e consumatori attraverso sequenze.

Quindi produttori e consumatori non si calpestano all'interno dell'array circolare controllando le loro sequenze corrispondenti . E per comunicare le loro sequenze avanti e indietro, usano barriere di memoria anziché blocchi. Questo è il modo più veloce senza blocchi che possono comunicare.

Fortunatamente non è necessario scendere ai dettagli interni del modello di disgregatore per usarlo. Oltre all'implementazione di LMAX c'è CoralQueue sviluppato da Coral Blocks, con cui sono affiliato. Alcune persone trovano più semplice comprendere un concetto leggendo il codice, quindi di seguito è riportato un semplice esempio di un singolo produttore che invia messaggi a un singolo consumatore. Puoi anche controllare questa domanda per un esempio di demultiplexer (da un produttore a molti consumatori).

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();
    }
}

Disclaimer: sono uno degli sviluppatori di CoralQueue.


1
Sarebbe bello dichiarare la tua affiliazione con il software che descrivi.
Deer Hunter,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.