一种替代的多生产者方法

最近在InfoQ上,Aliasei Papou发表了一篇关于他的一些实验的文章 ,该实验在线程之间进行了高性能的消息交换。 本文中有许多示例,但我将重点介绍多生产者案例。 文章显示的一种优化方法是,如果您知道初始化时拥有的生产者数量,则可以构建一个可以大大减少竞争的结构。 现有的MultiProducerSequencer不具有此约束,这对于大量用例而言是必不可少的。 但是,我想看看如果将这种方法应用于Disruptor,我们可以实现什么。

我要使用的设计是,不是使用MultiProducerSequencer使用单个Disruptor,而是使用每个生产者使用SingleProducerSequencer的每个Disruptor。 为了使所有事件通道进入单个EventHandler,我将需要实现一个自定义EventProcessor,它具有轮询多个SequenceBarrier / DataProvider的能力。 在性能测试的com.lmax.disruptor.support程序包中可以看到此自定义MultiBufferBatchEventProcesor 。 该类的关键组件是主循环,可以在这里看到:

while (true)
{
    try
    {
        for (int i = 0; i < barrierLength; i++)
        {
            long available = barriers[i].waitFor(-1);
            Sequence sequence = sequences[i];

            long previous = sequence.get();

            for (long l = previous + 1; l <= available; l++)
            {
                handler.onEvent(providers[i].get(l), l, previous == available);
            }

            sequence.set(available);

            count += (available - previous);
        }

        Thread.yield();
    }
    // Lines omitted...
}

这种方法的核心是事件处理器将2个数组传递到其构造函数中:

  • 数据提供者[]; 环形缓冲区数组,用于从中读取数据。
  • SequenceBarrier []; 每个环形缓冲区提供的屏障。

由此事件处理器将构造一个Sequence数组,该数组将用于跟踪来自每个环形缓冲区的已处理事件。 事件循环将遍历序列屏障,以确定是否有任何环形缓冲区具有可读取的数据。 任何可用的数据都将传递到用户提供的事件处理程序上。

为了测试这一点,我创建了ThreeToThreeSequencedThroughputTest ,该测试启动了三个生产者和一个消费者。 InfoQ文章中提供的代码的方面之一是,每列火车的容量为三长,而“运”则以一长的运动量度。 为了使测试更具可比性,我在环形缓冲区中使用了一个由三个long组成的数组作为条目,并将线程之间移动的事件总数乘以3,以计算出总的“ ops”。

测试结果(英特尔®酷睿™i7-3770 CPU @ 3.40GHz)

干扰者:

Run 0, Disruptor=390,738,060 ops/sec
Run 1, Disruptor=387,931,034 ops/sec
Run 2, Disruptor=397,058,823 ops/sec
Run 3, Disruptor=394,160,583 ops/sec
Run 4, Disruptor=396,767,083 ops/sec
Run 5, Disruptor=394,736,842 ops/sec
Run 6, Disruptor=396,767,083 ops/sec

铁路/火车:

ops/sec       = 243,141,801
ops/sec       = 302,695,445
ops/sec       = 283,096,862
ops/sec       = 273,670,298
ops/sec       = 268,340,387
ops/sec       = 264,802,500
ops/sec       = 262,258,028

显然,这种方法有一些优点。 我正在考虑将此添加到主要Disruptor发行版中。 但是,我仍然需要先解决几个设计问题。

传递给处理程序的序列值是来自源环形缓冲区的值,并且可能随着事件的流逝而上升和下降,我不确定这是否会对用户造成问题。 感觉这是一件相当次要的事情,所以希望我不必担心。 事件处理器目前仅支持yield。 我需要弄清楚如何正确地包含等待策略,因为阻塞等待策略和消费者唤醒会带来一些麻烦。

这个想法是我们在邮件列表上提到的,我最初并不特别感兴趣,但是鉴于这种方法有明显的好处,我想我会更认真地对待这个想法。

参考:来自Bad Concurrency博客的JCG合作伙伴 Michael Barker 的替代性多生产者方法

翻译自: https://www.javacodegeeks.com/2013/12/an-alternative-multi-producer-approach.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值