disruptor_harden vol1disruptor_lmax.disruptorr(2)

电脑杂谈  发布时间:2017-02-24 20:15:19  来源:网络整理

这就是伪共享,因为每次你访问A的同时,你也会得到B,而且每次你访问B,同时你也会得到A。他们仿佛是一体的,但是实际没有任何关系。

引入缓存行填充机制,在RingBuffer中,需要有一个指向当前数据区的序列号(Sequencer),在有生成者和消费者对RingBuffer进行,数据读写的时候,我们对这个序列号进行缓存行填充机制,保证一个序列号在内存中,占有一个缓冲行。

通过代码演示,我们也可以看到的确存在差异,而且随着读写的线程变多,这样的差距越大。

false share code

官方给到的代码,没有进行完全填充(也就是没有沾满一个缓存行),我自己写的例子有进行改进。

在典型的消费者/生成者模型中,会存在等待现象,disruptor提供了以下的几种等待策略:

BlockingWaitStrategy 是最低效的策略,但其对CPU的消耗最小并且在各种不同部署环境中能提供更加一致的性能表现

SleepingWaitStrategy 的性能表现跟 BlockingWaitStrategy 差不多,对 CPU 的消耗也类似,但其对生产者线程的影响最小,适合用于异步日志类似的场景;

YieldingWaitStrategy 的性能是最好的,适合用于低延迟的系统。在要求极高性能且事件处理线数小于 CPU 逻辑核心数的场景中,推荐使用此策略;例如,CPU开启超线程的特性。

经测试前两种效果差不多,延迟在微秒以内,可以忽略,cpu占用不高,YieldingWaitStrategy模式队列空闲时CPU达到100%,不适合

简单例子

直接使用ringbuffer

public static void main(String[] args) {
    int size = 1<<10;
    ExecutorService executors = Executors.newCachedThreadPool();
    //创建一个disruptor,指定ringbuffer的size和处理数据的factory
    Disruptor<TestObject> disruptor = new Disruptor<TestObject>(new TestObjectFactory(), size, executors);
    //disruptor里面设置一个处理方式
    disruptor.handleEventsWith(new TestObjectHandler());
    RingBuffer<TestObject> ringBuffer = disruptor.start();
    for (long i = 0; i < 1000; i++) {
    //下一个可以用的序列号
        long seq = ringBuffer.next();
        try {
            //这个序列号的slot 放入数据    
            TestObject valueEvent = ringBuffer.get(seq);
            valueEvent.setValue(i);
        } finally {
            //发布通知,并且这一步一定要放在finally中,因为调用了ringBuffer.next(),就一定要发布,否则会导致disruptor状态的错乱
            ringBuffer.publish(seq);
        }
    }
    disruptor.shutdown();
    executors.shutdown();
}


本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-34283-2.html

相关阅读
    发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

    • 李青骏
      李青骏

      雷达探测精度和灵敏度

    • 武玉贺
      武玉贺

      表示农民老了只能喝水了

    热点图片
    拼命载入中...