Quelqu'un peut-il expliquer en termes simples quel est le schéma de perturbation?

Réponses:

33

The Fowler Article fournit un bon guide, et cette explication:

Au niveau brut, vous pouvez considérer un perturbateur comme un graphe de multidiffusion de files d'attente où les producteurs y déposent des objets qui sont envoyés à tous les consommateurs pour une consommation parallèle via des files d'attente séparées en aval. Quand vous regardez à l'intérieur, vous voyez que ce réseau de files d'attente est en réalité une structure de données unique - un tampon en anneau.

Chaque producteur et consommateur a un compteur de séquence pour indiquer l'emplacement dans la mémoire tampon sur lequel il travaille actuellement. Chaque producteur / consommateur écrit son propre compteur de séquence mais peut lire les compteurs de séquence des autres. Ainsi, le producteur peut lire les compteurs des consommateurs pour s’assurer que le logement qu’il veut écrire est disponible sans aucun verrou sur les compteurs. De même, un consommateur peut s’assurer qu’il ne traite que les messages dès qu’un autre consommateur en a terminé en surveillant les compteurs.

entrez la description de l'image ici

Une approche plus conventionnelle pourrait utiliser une file d'attente de production et une file d'attente de consommateur, chacune utilisant des verrous comme mécanismes d'accès simultané. En pratique, ce qui se passe avec les files d'attente de producteurs et de consommateurs, c'est que ces dernières sont soit complètement vides, soit complètement pleines la plupart du temps, ce qui provoque des conflits de verrous et des cycles d'horloge inutiles. Le perturbateur atténue cela, en partie, en faisant en sorte que tous les producteurs et consommateurs utilisent le même mécanisme de file d'attente, se coordonnant les uns avec les autres en surveillant les compteurs de séquence plutôt qu'en utilisant des mécanismes de verrouillage.

Robert Harvey
la source
9

De cet article sur CoralQueue :

Le modèle de perturbateur est une file d'attente de traitement par lots sauvegardée par un tableau circulaire (le tampon en anneau) rempli d'objets de transfert pré-alloués, qui utilise des barrières de mémoire pour synchroniser les producteurs et les consommateurs à travers des séquences.

Les producteurs et les consommateurs ne se chevauchent donc pas à l'intérieur du réseau circulaire en vérifiant leurs séquences correspondantes . Et pour communiquer leurs séquences dans les deux sens, ils utilisent des barrières de mémoire au lieu de verrous. C'est le moyen le plus rapide sans verrouillage de communiquer.

Heureusement, vous n'avez pas besoin de vous attaquer aux détails internes du modèle de disjoncteur pour l'utiliser. Outre l'implémentation LMAX, CoralQueue a été développé par Coral Blocks, auquel je suis affilié. Certaines personnes trouvent plus facile de comprendre un concept en lisant du code. Vous trouverez ci-dessous un exemple simple de producteur qui envoie des messages à un seul consommateur. Vous pouvez également vérifier cette question pour un exemple de démultiplexeur (un producteur à plusieurs consommateurs).

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: Je suis l'un des développeurs de CoralQueue.

Rdalmeida
la source
1
Ce serait bien de préciser votre affiliation avec le logiciel que vous décrivez.
Deer Hunter