我已经了解了LMAX这个名为RingBuffer的精彩概念。 所以大家告诉我,当只用一个线程写入ringbuffer时,性能比多个生产者更好......
然而,我真的没有发现tipical应用程序只能使用一个线程在ringbuffer上写入...我真的不明白lmax是如何做的(如果他们这样做)。例如,N个不同的交易者在交易所下订单,那些都是异步请求,它们被转换为订单并放入ringbuffer,他们怎么可能用一个线程写那些?
问题1.我可能会遗漏某些内容或误解某些方面,但如果您有N个并发生产者,如何将它们合并为1并且不能互相锁定?
问题2.我记得rxJava observables,您可以使用Observable.merge将N个可观察对象合并为1,我想知道它是否阻塞或以任何方式保持任何锁定?
答案 0 :(得分:3)
多线程写入对RingBuffer的影响很小,但在非常重的负载下可能会很重要。
RingBuffer实现包含next
节点,其中将进行下一次添加。如果只有一个主题写入环,则该过程将始终在最短时间内完成,即buffer[head++] = newData
。
要在避免锁定的同时处理多线程,通常会执行while ( !buffer[head++].compareAndSet(null,newValue)){}
之类的操作。这个紧密的循环将继续执行,而其他线程正在干扰数据的存储,从而减慢了吞吐量。
请注意,我上面使用了伪代码,请查看我的实现here中的getFree
以获取真实示例。
// Find the next free element and mark it not free.
private Node<T> getFree() {
Node<T> freeNode = head.get();
int skipped = 0;
// Stop when we hit the end of the list
// ... or we successfully transit a node from free to not-free.
// This is the loop that could cause delays under hight thread activity.
while (skipped < capacity && !freeNode.free.compareAndSet(true, false)) {
skipped += 1;
freeNode = freeNode.next;
}
// ...
}
答案 1 :(得分:2)
在内部,RxJava的合并使用了一个序列化构造,我调用emitter-loop使用synchronized
并阻塞。
我们的客户&#39;使用合并主要是在吞吐量和延迟不敏感的情况下或完全单线程和阻塞不是真正的问题。
可以编写一个名为queue-drain的非阻塞序列化程序,但不能将合并配置为使用它。
您还可以查看JCTools&#39;如果您愿意手动处理生产者和消费者线程,则直接MpscArrayQueue
。