探讨互斥锁锁定非临界区带来多少性能消耗

2024-04-12 02:32

本文主要是介绍探讨互斥锁锁定非临界区带来多少性能消耗,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

概述

本次主要是测试使用互斥锁,锁定非临界区带来的性能消耗。

在我们写代码时,有时候通过逻辑的设计,可以使代码中临界区在80%以上不会同时访问。但是从理论上来说,在极端或者概率很低的情况下它是可能成为临界区的。处于程序的稳定性考虑,同样是需要加锁的。

但是最近在看disruptor文档[1]时,文献提到:

即使不是临界资源,只要调用了锁就会大幅度的降低性能。
而我之前在项目中的代码,总是会考虑逻辑上减少多线程去竞争同一个锁,这难道是在做无用功?

文中采用的是简单的做5亿次++操作,考虑到其是用Java实现的,因此此处采用C来实现,实践来检验一下结果

 

如果有资源竞争,肯定会导致性能下降。因此我们主要对比进入“假临界区"的场景。

 

测试代码:

 

点击(此处)折叠或打开

  1. #include<stdio.h>
  2. #include<time.h>
  3. #include<sys/time.h>
  4. #include<unistd.h>
  5. #include<string.h>
  6.  
  7. #include<pthread.h>
  8.  
  9.  
  10. unsigned long gtimes = 2 * 1000 * 1000 * 1000;
  11. unsigned long i;
  12.  
  13. struct timeval startTime, endTime;
  14.  
  15. pthread_mutex_t gmutex; //ensure not a stack varible;
  16.  
  17. void start_time()
  18. {
  19.     gettimeofday(&startTime, NULL);
  20. }
  21.  
  22. void end_time()
  23. {
  24.     gettimeofday(&endTime, NULL);
  25. }
  26.  
  27. double spend_time()
  28. {
  29.     return 1000 * (endTime.tv_sec - startTime.tv_sec) +
  30.         (endTime.tv_usec - startTime.tv_usec) / 1000.0f;
  31. }
  32.  
  33. void* test_thread(void* argv)
  34. {
  35.     i = gtimes;
  36.  
  37.     start_time();
  38.     while(i--);
  39.     end_time();
  40.  
  41.     printf(" a thread cost time: %.2f ms\n", spend_time());
  42.  
  43.     return NULL;
  44. }
  45.  
  46. void* test_lockthread(void* argv)
  47. {
  48.     i = gtimes;
  49.     pthread_mutex_init(&gmutex,NULL);
  50.  
  51.     start_time();
  52.  
  53.     pthread_mutex_lock(&gmutex);
  54.     while(i--);
  55.     pthread_mutex_unlock(&gmutex);
  56.  
  57.     end_time();
  58.  
  59.     pthread_mutex_destroy(&gmutex);
  60.     printf(" a thread with a pthread_mutex, cost time: %.2f ms\n", spend_time());
  61.  
  62.     return NULL;
  63. }
  64. int main(int argc, char *argv[])
  65. {
  66.     pthread_t pid;
  67.  
  68.     //pthread_create(&pid, NULL, test_thread, NULL);
  69.     pthread_create(&pid, NULL, test_lockthread, NULL);
  70.  
  71.     pthread_join(pid, NULL);
  72.  
  73.     test_thread(NULL);
  74.     test_lockthread(NULL);
  75.  
  76.     return 0;
  77. }


测试结果:

 不加锁加锁效率对比绝对值加锁在不同线程
1990.861007.291.66%16.43987.79
2996.13997.040.09%0.911001.21
3988.47989.190.07%0.72982.72
4993.6992.02-0.16%-1.58986.94
5984.85984.57-0.03%-0.28989.66
6991.59986.75-0.49%-4.84992.94
7986.68986.720.00%0.04983.4
8989.16991.170.20%2.01987.69
9987.221001.311.43%14.09985.03
10986.27984.09-0.22%-2.18987.14

 

从上表可以看出:
如果两个场景在不同的线程中,没有可比性:两者差值不同。
再考虑到进程调度。理论上偏差也比较大

如果是同一个线程中,除了第1和第9组数据,差距都不是很大:
最大偏差<2ms,偏差率<0.5%.
多数偏差<1ms,偏差率<0.1%.

那么另外两组误差在哪里呢?同样是时间片。Linux中时间片是10ms。
在程序中,两个函数是挨着执行的,如果第一个函数执行完成之后,在执行第二个函数的start_time后时间片到期,此时就会多消耗一个时间片。
那么我们将后一个函数减去时间片,则基本上可以在接收的范围内——实际上还会有至少两次线程切换

1990.86997.290.65%6.43987.79
9987.22991.310.41%4.09985.03

 

结论:

C 中的锁即使进入临界区,实际没有发生资源争用,基本上等同于进入非临界区。

但是性能消耗肯定是有的,应该是锁底层实现的首先自旋的时候会识别出来资源可用!

 

[1] disruptor原文地址:https://mechanitis.blogspot.jp/2011/07/dissecting-disruptor-why-its-so-fast.html

http://blog.chinaunix.net/uid-28993794-id-5779757.html

这篇关于探讨互斥锁锁定非临界区带来多少性能消耗的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/895857

相关文章

JVisualVM之Java性能监控与调优利器详解

《JVisualVM之Java性能监控与调优利器详解》本文将详细介绍JVisualVM的使用方法,并结合实际案例展示如何利用它进行性能调优,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全... 目录1. JVisualVM简介2. JVisualVM的安装与启动2.1 启动JVisualVM2

Java使用MethodHandle来替代反射,提高性能问题

《Java使用MethodHandle来替代反射,提高性能问题》:本文主要介绍Java使用MethodHandle来替代反射,提高性能问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑... 目录一、认识MethodHandle1、简介2、使用方式3、与反射的区别二、示例1、基本使用2、(重要)

Java内存区域与内存溢出异常的详细探讨

《Java内存区域与内存溢出异常的详细探讨》:本文主要介绍Java内存区域与内存溢出异常的相关资料,分析异常原因并提供解决策略,如参数调整、代码优化等,帮助开发者排查内存问题,需要的朋友可以参考下... 目录一、引言二、Java 运行时数据区域(一)程序计数器(二)Java 虚拟机栈(三)本地方法栈(四)J

PyTorch高级特性与性能优化方式

《PyTorch高级特性与性能优化方式》:本文主要介绍PyTorch高级特性与性能优化方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、自动化机制1.自动微分机制2.动态计算图二、性能优化1.内存管理2.GPU加速3.多GPU训练三、分布式训练1.分布式数据

Java的"伪泛型"变"真泛型"后对性能的影响

《Java的伪泛型变真泛型后对性能的影响》泛型擦除本质上就是擦除与泛型相关的一切信息,例如参数化类型、类型变量等,Javac还将在需要时进行类型检查及强制类型转换,甚至在必要时会合成桥方法,这篇文章主... 目录1、真假泛型2、性能影响泛型存在于Java源代码中,在编译为字节码文件之前都会进行泛型擦除(ty

Python实现微信自动锁定工具

《Python实现微信自动锁定工具》在数字化办公时代,微信已成为职场沟通的重要工具,但临时离开时忘记锁屏可能导致敏感信息泄露,下面我们就来看看如何使用Python打造一个微信自动锁定工具吧... 目录引言:当微信隐私遇到自动化守护效果展示核心功能全景图技术亮点深度解析1. 无操作检测引擎2. 微信路径智能获

使用Python实现一键隐藏屏幕并锁定输入

《使用Python实现一键隐藏屏幕并锁定输入》本文主要介绍了使用Python编写一个一键隐藏屏幕并锁定输入的黑科技程序,能够在指定热键触发后立即遮挡屏幕,并禁止一切键盘鼠标输入,这样就再也不用担心自己... 目录1. 概述2. 功能亮点3.代码实现4.使用方法5. 展示效果6. 代码优化与拓展7. 总结1.

Python如何使用__slots__实现节省内存和性能优化

《Python如何使用__slots__实现节省内存和性能优化》你有想过,一个小小的__slots__能让你的Python类内存消耗直接减半吗,没错,今天咱们要聊的就是这个让人眼前一亮的技巧,感兴趣的... 目录背景:内存吃得满满的类__slots__:你的内存管理小助手举个大概的例子:看看效果如何?1.

Redis中高并发读写性能的深度解析与优化

《Redis中高并发读写性能的深度解析与优化》Redis作为一款高性能的内存数据库,广泛应用于缓存、消息队列、实时统计等场景,本文将深入探讨Redis的读写并发能力,感兴趣的小伙伴可以了解下... 目录引言一、Redis 并发能力概述1.1 Redis 的读写性能1.2 影响 Redis 并发能力的因素二、

Golang中拼接字符串的6种方式性能对比

《Golang中拼接字符串的6种方式性能对比》golang的string类型是不可修改的,对于拼接字符串来说,本质上还是创建一个新的对象将数据放进去,主要有6种拼接方式,下面小编就来为大家详细讲讲吧... 目录拼接方式介绍性能对比测试代码测试结果源码分析golang的string类型是不可修改的,对于拼接字