最近研究boost的无锁队列,测试了一下性能,发现无锁队列比有锁的还要慢

testqueue.cpp

#include <time.h>
#include <boost/thread/thread.hpp>
#include <boost/lockfree/queue.hpp>
#include <iostream>

#include <boost/atomic.hpp>

boost::atomic_int producer_count(0);
boost::atomic_int consumer_count(0);

boost::lockfree::queue<int> queue(128);//无锁的多生产者多消费者队列

const int iterations = 100000;
const int producer_thread_count = 1;
const int consumer_thread_count = 1;

void producer(void)
{
    for (int i = 0; i != iterations; ++i) {
        int value = ++producer_count;
        //std::cout<<"product value:"<<value<<std::endl;
        while (!queue.push(value))
            ;
    }
}

boost::atomic<bool> done (false);
void consumer(void)
{
    int value;
    while (!done) {
        while (queue.pop(value))
        {
        //      std::cout<<"customer value:"<<value<<std::endl;
            ++consumer_count;
        }
    }

while (queue.pop(value))
        {
        //      std::cout<<"customer value:"<<value<<std::endl;
                ++consumer_count;
        }
}

int main(int argc, char* argv[])
{
    using namespace std;
    cout << "boost::lockfree::queue is ";
    if (!queue.is_lock_free())
        cout << "not ";
    cout << "lockfree" << endl;

boost::thread_group producer_threads, consumer_threads;//线程组

for (int i = 0; i != producer_thread_count; ++i)
        producer_threads.create_thread(producer);

for (int i = 0; i != consumer_thread_count; ++i)
        consumer_threads.create_thread(consumer);

producer_threads.join_all();
    done = true;

consumer_threads.join_all();

cout << "produced " << producer_count << " objects." << endl;
    cout << "consumed " << consumer_count << " objects." << endl;
    //getchar();
}

#include <time.h>
#include <boost/thread/thread.hpp>
#include <boost/lockfree/queue.hpp>
#include <iostream>
#include <queue>

#include <boost/atomic.hpp>

boost::atomic_int producer_count(0);
boost::atomic_int consumer_count(0);

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;/*初始化互斥锁*/

std::queue<int> queue2;//无锁的多生产者多消费者队列

const int iterations = 100000;
const int producer_thread_count = 1;
const int consumer_thread_count = 1;

void producer(void)
{
    for (int i = 0; i != iterations; ++i) {

int value = ++producer_count;
        //std::cout<<"product value:"<<value<<std::endl;
        pthread_mutex_lock(&mutex); //互斥锁
        queue2.push(value);
        pthread_mutex_unlock(&mutex); //互斥锁
    }
}

boost::atomic<bool> done (false);
void consumer(void)
{
    int value;
    while (!done) {
        pthread_mutex_lock(&mutex); //互斥锁
        int value = 0;
        if(!queue2.empty()) {
                value = queue2.front();
                queue2.pop();
        }
        pthread_mutex_unlock(&mutex); //互斥锁
        {
        //      std::cout<<"customer value:"<<value<<std::endl;
                ++consumer_count;
        }
    }

pthread_mutex_lock(&mutex); //互斥锁
    while (!queue2.empty()) {
        int value = 0;
        value = queue2.front();
        queue2.pop();
        {
          //      std::cout<<"customer value:"<<value<<std::endl;
                ++consumer_count;
        }
    }
    pthread_mutex_unlock(&mutex); //互斥锁
}

int main(int argc, char* argv[])
{
    using namespace std;
    cout << "boost::lockfree::queue is ";
    //if (!queue.is_lock_free())
    //    cout << "not ";
    cout << "lockfree" << endl;
    pthread_mutex_init(&mutex, NULL);
    boost::thread_group producer_threads, consumer_threads;//线程组

for (int i = 0; i != producer_thread_count; ++i)
        producer_threads.create_thread(producer);

for (int i = 0; i != consumer_thread_count; ++i)
        consumer_threads.create_thread(consumer);

producer_threads.join_all();
    done = true;

consumer_threads.join_all();

pthread_mutex_destroy(&mutex);
    cout << "produced " << producer_count << " objects." << endl;
    cout << "consumed " << consumer_count << " objects." << endl;
    //getchar();
}

time ./testqueue
boost::lockfree::queue is lockfree
produced 100000 objects.
consumed 100000 objects.

real    0m0.054s
user    0m0.103s
sys     0m0.002s

time ./testqueue2
boost::lockfree::queue is lockfree
produced 100000 objects.
consumed 100000 objects.

real    0m0.024s
user    0m0.032s
sys     0m0.008s

无锁比有锁慢了一倍,如果将线程数都调整为4,2个速度都差不多

看另外地方写的原因:

https://blog.csdn.net/cws1214/article/details/47680773?utm_source=blogxgwz8

无锁队列与有锁队列的性能测试

这里测试的无锁列队由 MidiShare 实现的,而有锁队列是通过 pthread_mutex 与 c++ 的 STL list 共同实现。这里只列出测试结果。

对于存储相同的数据的情况下,从主线程 enque 并从子线程 deque ,计算每秒钟 enque/deque 的次数,当然二者基本上是相同的。

无锁队列的性能在 150w -200w 次入队操作,这个性能已经无法再有任何提高,因为每次入队出队操作都是硬件级的互斥。而对于有锁队列,根据每次加解锁之间处理入队的次数的不同,有以下的结果:

lock();for(k=0;k<x;i++,k++);unlock()

结果(次/s)

x=1

40 万

x=10

190 万

x=128

350 万

x=1000

400 万

x=10000

396 万

这说明通过对锁之间的数据进行批处理,可以极大的提高系统的性能,而使用原子操作,则无法实现批处理上的改进。

4 结论

通过上面的无锁和有锁的性能测试,可以得出这样的结论,对于 CAS 实现的硬件级的互斥,其单次操作性能比相同条件下的应用层的较为高效,但当多个线程并发时,硬件级的互斥引入的代价与应用层的锁争用同样令人惋惜。因此如果纯粹希望通过使用 CAS 无锁算法及相关数据结构而带来程序性能的大量提升是不可能的,硬件级原子操作使应用层操作变慢,而且无法再度优化。相反通过对有锁多线程程序的良好设计,可以使程序性能没有任何下降,可以实现高度的并发性。

但是我们也要看到应用层无锁的好处,比如不需要程序员再去考虑死锁、优先级反转等棘手的问题,因此在对应用程序不太复杂,而对性能要求稍高时,可以采用有锁多线程。而程序较为复杂,性能要求满足使用的情况下,可以使用应用级无锁算法。

至于如何对多线程的工作模式进行更好的调度,可以参考文献 [5] ,文献介绍了一种较好的线程间合作的工作模式,当然前提是机器的处理器个数较多,足以支持多组线程并行的工作。如果处理器个数较,较多的线程之间在各个核心上来回调度增加了系统上下文切换的开销,会导致系统整体性能下降。

可能无锁使用的是硬件层的原子锁,所有线程都会不可避免竞争这个原子锁,性能可能有限,而应用层的锁会有所优化

无锁队列与有锁队列性能比较相关推荐

  1. 无锁编程与有锁编程的效率总结、无锁队列的实现(c语言)

    1.无锁编程与有锁编程的效率 无锁编程,即通过CAS原子操作去控制线程的同步.如果你还不知道什么使CAS原子操作,建议先去查看相关资料,这一方面的资料网络上有很多. CAS实现的是硬件级的互斥,在线程 ...

  2. java的“看门狗”锁续期可以用php redis这样实现【php锁续期、分布式锁、无锁请求队列超卖】解决【商家超卖(商品库存控制)、用户超买(秒杀订单控制)】问题。非demo 线上一直在用

    要求与痛点描述 1.不允许使用库存创建队列 因为库存如果是10w难道要创建一个10w长度的队列吗 2.不允许对整个业务过程加锁 可能业务执行时间很长 导致锁粒度太大 影响并发量 3.如果业务时间大于锁 ...

  3. 闲聊AQS面试和源码解读---可重入锁、LockSupport、CAS;从ReentrantLock源码来看公平锁与非公平锁、AQS到底是怎么用CLH队列来排队的?

    AQS原理可谓是JUC面试中的重灾区之一,今天我们就来一起看看AQS到底是什么? 这里我先整理了一些JUC面试最常问的问题? 1.Synchronized 相关问题以及可重入锁 ReentrantLo ...

  4. java8 同步队列_秋招之路8:JAVA锁体系和AQS抽象队列同步器

    整个的体系图 悲观锁,乐观锁 是一个广义概念:体现的是看待线程同步的不同角度. 悲观锁 认为在自己使用数据的时候一定有别的线程来修改数据,在获取数据的时候会先加锁,确保数据不被别的线程修改. 实现:关 ...

  5. 使用ZooKeeper实现分布式队列、分布式锁和选举详解

    点击关注公众号,实用技术文章及时了解 来源:blog.csdn.net/qq_40378034/ article/details/117014648 ZooKeeper源码的zookeeper-rec ...

  6. 进程同步控制(锁,信号量,事件), 进程通讯(队列和管道,生产者消费者模型) 数据共享(进程池和mutiprocess.Pool模块)...

    参考博客 https://www.cnblogs.com/xiao987334176/p/9025072.html#autoid-1-1-0 进程同步(multiprocess.Lock.Semaph ...

  7. 【高并发秒杀系统】对分布式锁、缓存、消息队列、限流等的原理分析及代码实现

    前言:在一些商城项目中,秒杀是不可或缺的.但是,如果将普通的购买.消费等业务流程用于秒杀系统,不做任何的处理,会导致请求阻塞严重.超买超卖等严重后果,服务器.数据库也可能因为瞬时的流量而奔溃.所以,设 ...

  8. 释放锁以及添加线程对于队列的变化

    当出现锁竞争以及释放锁的时候,AQS同步队列中的节点会发生变化,首先看一下添加节点的场景. 里会涉及到两个变化 1. 新的线程封装成Node节点追加到同步队列中,设置prev节点以及修改当前节点的前置 ...

  9. 进程锁、事件、进程队列、进程间共享数据、生产者消费者模型

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 进程锁(Lock) 锁的基本概念 锁的基本用法 模拟12306抢票软件 信号量:Semaphone 概念 Semaphore ...

最新文章

  1. 求解单源最短路径的几种算法
  2. ping 代理_Happy专访:Ping太高不是问题 换我不会像120一样比赛
  3. Linux_PXE服务器_RHEL7
  4. Linux 软件包管理命令
  5. kvm cobbler无人值守批量安装操作系统
  6. RabbitMQ消息追踪之rabbitmq_tracing
  7. 如何选择数据结构和算法(转)
  8. go 简单的RPC服务与客户端通讯
  9. Java实现二维码生成
  10. linuxweb服务器域名网站,linux web服务器目录
  11. hive和mysql传输数据类型_hive的数据类型
  12. 13.业务层的事务操作
  13. 如何理解和使用Java package包
  14. 为了有利于保护安全性,IE已限制此网页运行可以访问计算机的脚本或 ActiveX 控件。请单击这里获取选项......
  15. php 时分秒转时分_php 时分秒转为秒,秒转化为天时分秒
  16. c语言 空心的倒三角形,C语言题目,请根据要求打印可空心倒三角形
  17. cad批量等高线lisp_基于AutoCAD Lisp局部等高线自动内插新方法
  18. 编写一个函数模板,实现两个对象大小的比较,并按照需求返回较大者或较小者。
  19. “中国童装之都”牵手九州云,共建智慧园区促产业转型
  20. ssm和springboot的区别

热门文章

  1. 电脑端无需下载软件制作动图教程
  2. lombok构造模式
  3. STM32F030xx硬件SPI调试记录
  4. 最新cocos2d-x 3.0博客教学 小游戏[史上最坑爹的游戏] 001主画面以及关卡选择画面的制作
  5. [4G5G专题-47]:物理层-多天线MIMO技术、层映射、预编码矩阵
  6. (书摘)牛奶可乐经济学之成本效益原则
  7. 为何会考虑MES系统云部署
  8. 机器学习-准备 scikit-learn-Orange安装
  9. 何谓BLDC电机?BLDC电机是如何旋转的?
  10. 普中科技MicroPython基于esp32的基础教程-01-基础知识