Мені хотілося б, якби ви могли пояснити мені простим способом, як працює малюнок руйнування. Ця концепція була мені невловимою, як відомо.
Можливо, з вашою допомогою я міг би це зрозуміти.
Мені хотілося б, якби ви могли пояснити мені простим способом, як працює малюнок руйнування. Ця концепція була мені невловимою, як відомо.
Можливо, з вашою допомогою я міг би це зрозуміти.
Відповіді:
У Fowler статті постачальники хороший праймер, і це пояснення:
На високому рівні ви можете розглядати Disruptor як графік багатосторонніх очеретів, де виробники ставлять на нього об'єкти, які надсилаються всім споживачам для паралельного споживання через окремі черги нижче за течією. Заглянувши всередину, ви побачите, що ця мережа черг - це справді єдина структура даних - кільцевий буфер.
Кожен виробник і споживач має лічильник послідовностей, щоб вказати, який слот у буфері працює над цим. Кожен виробник / споживач пише власний лічильник послідовностей, але може читати лічильники послідовностей інших. Таким чином виробник може читати лічильники споживачів, щоб переконатися, що слот, в який він хоче записати, доступний без жодних замків на лічильниках. Так само споживач може забезпечити, що він обробляє повідомлення лише після того, як з ним буде зроблено інший споживач, спостерігаючи за лічильниками.
Більш традиційний підхід може використовувати Чергу виробників і Чергу споживачів, кожен з яких використовує блокування як механізми одночасності. На практиці те, що трапляється з чергами виробників та споживачів, - це те, що черги є або повністю порожніми, або повністю заповненими більшу частину часу, що спричиняє суперечки із блокуванням та марними циклами годин. Зривник усуває це частково тим, що всі виробники та споживачі використовують один і той же механізм черги, координуючи один з одним перегляд лічильників послідовностей, а не використання механізмів блокування.
З цієї статті про CoralQueue :
Шаблон розриву - це чергова черга, підкріплена круговим масивом (тобто кільцевим буфером), заповненим попередньо виділеними об'єктами передачі, який використовує бар'єри пам'яті для синхронізації виробників і споживачів за допомогою послідовностей.
Тож виробники та споживачі не наступають один на одного всередині кругового масиву , перевіряючи їх відповідні послідовності . А для передачі послідовностей взагалі та назад вони використовують бар'єри пам'яті замість замків. Це найшвидший спосіб блокування без блокування.
На щастя, вам не потрібно зводитися до внутрішніх деталей схеми руйнування, щоб використовувати її. Окрім впровадження LMAX, є CoralQueue, розроблена Coral Blocks, з якою я пов'язаний. Деяким людям легше зрозуміти поняття, читаючи код, тому нижче - простий приклад того, як один виробник надсилає повідомлення одному споживачеві. Ви також можете перевірити це питання на прикладі демультиплексора (одного виробника для багатьох споживачів).
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();
}
}
Відмова: Я один із розробників CoralQueue.