无锁队列与有锁队列性能比较

最近研究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
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值