Concurrency LMAX';什么是破坏者模式工作?
我正在努力理解这个问题。我看了InfoQ视频,并试图阅读他们的论文。我知道这涉及到一个环形缓冲区,它被初始化为一个非常大的数组,以利用缓存的局部性,消除新内存的分配 听起来好像有一个或多个原子整数可以跟踪位置。每个“事件”似乎都有一个唯一的id,它在环中的位置是通过找到它相对于环大小的模数来确定的,等等 不幸的是,我对它的工作原理没有直觉。我做过很多交易申请,研究过SEDA等 在他们的演讲中,他们提到这种模式基本上就是路由器的工作原理;然而,我也没有找到任何关于路由器工作原理的好描述Concurrency LMAX';什么是破坏者模式工作?,concurrency,latency,actor,disruptor-pattern,Concurrency,Latency,Actor,Disruptor Pattern,我正在努力理解这个问题。我看了InfoQ视频,并试图阅读他们的论文。我知道这涉及到一个环形缓冲区,它被初始化为一个非常大的数组,以利用缓存的局部性,消除新内存的分配 听起来好像有一个或多个原子整数可以跟踪位置。每个“事件”似乎都有一个唯一的id,它在环中的位置是通过找到它相对于环大小的模数来确定的,等等 不幸的是,我对它的工作原理没有直觉。我做过很多交易申请,研究过SEDA等 在他们的演讲中,他们提到这种模式基本上就是路由器的工作原理;然而,我也没有找到任何关于路由器工作原理的好描述 有没有更好
有没有更好的解释呢?谷歌代码项目在环形缓冲区的实现方面做得很好,但是对于想要了解它是如何工作的人来说,这有点枯燥、学术和困难。然而,也有一些博客文章已经开始以更易读的方式解释内部内容。有一个是中断器模式的核心,一个(与从中断器读取相关的部分)和一些可用的 对破坏者最简单的描述是:它是一种以最有效的方式在线程之间发送消息的方法。它可以作为队列的替代品,但它也与SEDA和Actors共享许多特性 与队列相比: 破坏者提供了将消息传递到另一个线程的能力,在需要时将其唤醒(类似于阻塞队列)。然而,有三个明显的区别
onEndOfBatch()
。这允许较慢的使用者,例如,那些进行I/O以将事件批处理在一起以提高吞吐量的使用者。在其他Actor框架中进行批处理是可能的,但是几乎所有其他框架都不在批处理结束时提供回调,因此需要使用超时来确定批处理的结束,从而导致较差的延迟另一种方式是把它看作一个结构化、有序的记忆屏障。生产者屏障形成写屏障,消费者屏障形成读屏障。首先,我们想了解它提供的编程模型 有一个或多个作者。有一个或多个读卡器。有一行条目,完全按照从旧到新的顺序排列(图中为从左到右)。编写器可以在右端添加新条目。每个读卡器从左到右顺序读取条目。显然,读者无法阅读过去的作家 没有条目删除的概念。我使用“reader”而不是“consumer”来避免条目被消费的图像。然而,我们知道最后一个读卡器左边的条目是无用的 一般来说,读者可以同时阅读和独立阅读。但是,我们可以声明读取器之间的依赖关系。读取器依赖关系可以是任意非循环图。如果读卡器B依赖于读卡器A,则读卡器B不能读取超过读卡器A的内容 读卡器依赖性的产生是因为读卡器A可以对条目进行注释,而读卡器B依赖于该注释。例如,A对条目进行一些计算,并将结果存储在条目中的字段
A
。A然后继续,现在B可以读取条目,并存储A
A的值。如果读卡器C不依赖于A,则C不应尝试读取A
这确实是一个有趣的编程模型。无论性能如何,模型本身都可以
setNewEntry(EntryPopulator);
interface EntryPopulator{ void populate(Entry existingEntry); }
package com.coralblocks.coralqueue.sample.queue;
import com.coralblocks.coralqueue.AtomicQueue;
import com.coralblocks.coralqueue.Queue;
import com.coralblocks.coralqueue.util.MutableLong;
public class Sample {
public static void main(String[] args) throws InterruptedException {
final Queue<MutableLong> queue = new AtomicQueue<MutableLong>(1024, MutableLong.class);
Thread consumer = new Thread() {
@Override
public void run() {
boolean running = true;
while(running) {
long avail;
while((avail = queue.availableToPoll()) == 0); // busy spin
for(int i = 0; i < avail; i++) {
MutableLong ml = queue.poll();
if (ml.get() == -1) {
running = false;
} else {
System.out.println(ml.get());
}
}
queue.donePolling();
}
}
};
consumer.start();
MutableLong ml;
for(int i = 0; i < 10; i++) {
while((ml = queue.nextToDispatch()) == null); // busy spin
ml.set(System.nanoTime());
queue.flush();
}
// send a message to stop consumer...
while((ml = queue.nextToDispatch()) == null); // busy spin
ml.set(-1);
queue.flush();
consumer.join(); // wait for the consumer thread to die...
}
}