Я хотел бы, чтобы вы могли объяснить мне простым способом, как работает скороговорка. Эта концепция была неуловима для меня, как известно.
Возможно, с вашей помощью я мог бы понять это.
Я хотел бы, чтобы вы могли объяснить мне простым способом, как работает скороговорка. Эта концепция была неуловима для меня, как известно.
Возможно, с вашей помощью я мог бы понять это.
Ответы:
В 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.