背景
该篇博文是在看了一些文献,说是使用条件变量+互斥量会比使用信号量效率高,而以前看书的时候,觉得其它们是信号量的特例,直觉觉得只是简化了使用。虽然很多场景也没有必要使用信号量的计数,但是正如《win32 多线程程序设计》提的,有些场景必须使用(在没有条件变量的情况下)。因此测一下,条件变量与信号量的并发性能对比。
多线程的循环队列见另外本人的另外一篇博文(http://blog.chinaunix.net/uid-28993794-id-5770897.html)
由于另外两个版本的循环队列,以及完整的测试程序,代码显得有点多就不贴了,描述一下测试场景!(从该篇文章可以看出队列的一个并发问题,但是不影响测试)
概述
本文一共做了两次测试——结果看第二次测试就好了。第一次测试时是遇到了一点问题,以及有测试程序有BUG。第二次测试解决了此BUG,以及使用更大的数据来测试。
基本数据模型
每个生产者和消费者都为一个线程,各自向队列中放、取一个消息(多个消息只能一个一个放)。生产者不能向满队列中放消息,消费者不能消费空消息。如果条件不满足,阻塞直到满足条件。
一个消息,简单定义为:
点击(此处)折叠或打开
- class Student
- {
- public:
- Student() {}
- Student(const char* strName, int iAge, char chSex = 1):name(strName), age(iAge), sex(chSex){}
- stl_char32 name;
- int age;
- char sex;
- }
测试环境:
环境 | VMWare |
系统 | Centos7_x64 |
CPU | 1 |
内存 | 1GB |
测试结果
测试的思路为:每个生产者生产1万消息,调整生产者、消费者数量,缓冲区大小(循环队列大小),使并发数量达到最大。
但是测出来的数据有跳变的现象,经过分析,是总的测试时间太短导致误差。(数据没有实际参考意义就不贴了)。第二次将消息量改为了1亿,数据就比较相对比较稳定(条件变量还是有很大偏差,如果改为10亿偏差又会小很多,不过对于信号量来说执行时间过长。考虑到误差与对比的结果来说已经具有说服力,故还是采用1亿消息量进行测试)。
条件变量
生产者、消费者两个,缓冲区1万,消息量1亿。原始数据3组(时间单位为us,速率单位:笔/ms):
序号 | 消息数量 | 生产时间 | 生产速率 | 消费时间 | 消费者速率 |
1 | 100000000 | 33586668 | 2977.372 | 36325765 | 2752.867008 |
| 100000000 | 34083701 | 2933.954 | 36323483 | 2753.039955 |
2 | 100000000 | 33605133 | 2975.736 | 36979767 | 2704.181451 |
| 100000000 | 35280315 | 2834.442 | 36589686 | 2733.010609 |
3 | 100000000 | 35826637 | 2791.219 | 37227484 | 2686.187442 |
| 100000000 | 34924632 | 2863.309 | 37674271 | 2654.331387 |
从表中计算的平均值等,与程序统计的一致,此处就不整理表格了。
从该表可以看出,至少数字没有太大的跳变了,因此用该方法统计几组数据:
生产速率 | 消费者速率 | 差值 | 高多少 | 偏差 |
2903.37 | 2718.52 | 184.85 | 6.80% | 1.34% |
2955.5 | 2752.95 | 202.55 | 7.36% | 9.66% |
2826.8 | 2670.16 | 156.64 | 5.87% | -12.57% |
2993.23 | 2783.77 | 209.46 | 7.52% | 12.14% |
2924.19 | 2758.67 | 165.52 | 6.00% | -10.58% |
2950.77 | 2721.45 | 229.32 | 8.43% | 25.59% |
2874.57 | 2757.5 | 117.07 | 4.25% | -36.72% |
2918.347 | 2737.57429 | 180.7728571 | 6.71% |
|
|
| 直接算平均值 | 6.60% |
|
该表统计了生产速率和消费速率的关系——考虑了测试中的误差。
信号量
测试案例都一样:
生产速率 | 消费者速率 | 差值 | 高多少 |
844.108 | 844.289 | -0.181 | -0.02% |
843.285 | 844.689 | -1.404 | -0.17% |
851.864 | 851.705 | 0.159 | 0.02% |
841.78 | 838.346 | 3.434 | 0.41% |
836.372 | 835.402 | 0.97 | 0.12% |
从上面可以看出信号量的误差要小很多。
条件变量10亿:
信号量的误差较小,因此增加测试10亿部分,生产者和消费者速率分别是:2856.48、2675.15。比开始测出的数据还要小,因此将缓冲区增大到100万。结果分别是:2827.63、2679.1
从这里可以看出,似乎增大测试量,生产者和消费者的速率是在靠近的。但是无法证明。
说明:
测试时,CPU会持续100%,内存使用1万缓冲区0.1%,使用100万缓冲区4%。时间可以从表中看出。
总结
信号量速率比条件变量小很多(1/3)(信号量根据操作系统中标准的PV操作来实现的。)
同样的测试程序,且生产者和消费者都是做一次memcpy,信号量的生产者和消费者速率会更匹配一点。