- 浏览: 210425 次
最新评论
-
jin8000608172:
Profiler类是自己写的还是开源jar里面的,如果是开源j ...
isInfoEnabled究竟多有用? -
u011358822:
www.baidu.com
实战Concurrent -
u011358822:
[url][img][list][*]引用[/list][/i ...
实战Concurrent -
water_lang:
这本书我买了一本,但是我还是没找到该怎么解决事务这块,mong ...
《MongoDB实战》译者序 -
DREAM_UTOPIA:
每周推荐非常好,观点独到,涉及面广,谢谢
每周推荐阅读2013Q2汇总
前段时间,公司里组织了一次代码检查,其中有一条检查项让我有些费解:
理由是大量的不输出的日志对性能会有影响(日志中存在字符串拼接)。如果说只是DEBUG的加上,我也就认了,可是在系统中写成INFO的日志如果不输出,那还写它干嘛,我就是想看到关键路径的日志。而且在大多数日志上加上这么一个判断真的很难看。。。
所谓上有政策,下有对策,于是有人开始写一些包装了判断的辅助类,当中用这样的代码(截取):
public class LogUtil { public static void info(Logger logger, String message) { if (logger.isInfoEnabled()) { logger.info(message); } } public static void debug(Logger logger, String message) { if (logger.isDebugEnabled()) { logger.debug(message); } } public static void debug(Logger logger, String message, Throwable throwable) { if (logger.isDebugEnabled()) { logger.debug(message, throwable); } } }
但这样的代码真的就能解决问题了吗?答案是“不能”!字符串拼接还存在。
那让我们分两个部分来看一下这个问题:
- 日志中的字符串拼接真的对性能影响很大吗
- 加不加isInfoEnabled的性能差距究竟有多少
关于第一个问题,String的拼接是不修改原来的字符串的,而是创建一个新的String对象,道理上是这么说的,我们也该这么理解。但Java编译器并不傻,实际情况是怎么样的呢,它会做些优化。请看如下代码:
public class StringAddDemo { public static void main(String[] args) { String a = "abc"; String b = a + "def"; System.out.println(b + "ghi"); } }
在编译后,通过javap -c StringAddDemo看看结果:
public class StringAddDemo extends java.lang.Object{
public StringAddDemo();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: ldc #2; //String abc
2: astore_1
3: new #3; //class java/lang/StringBuilder
6: dup
7: invokespecial #4; //Method java/lang/StringBuilder."<init>":()V
10: aload_1
11: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/
String;)Ljava/lang/StringBuilder;
14: ldc #6; //String def
16: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/
String;)Ljava/lang/StringBuilder;
19: invokevirtual #7; //Method java/lang/StringBuilder.toString:()Ljava/la
ng/String;
22: astore_2
23: getstatic #8; //Field java/lang/System.out:Ljava/io/PrintStream;
26: new #3; //class java/lang/StringBuilder
29: dup
30: invokespecial #4; //Method java/lang/StringBuilder."<init>":()V
33: aload_2
34: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
37: ldc #9; //String ghi
39: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
42: invokevirtual #7; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
45: invokevirtual #10; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
48: return
}
实际这里的拼接用的是StringBuilder.append。情况没想的这么糟糕,而且1000次字符串拼接的开销都比不上一次远程调用的开销大,与其想着从这里挤性能,还不如去优化远程调用和数据库访问。
第二点,同样用实验来做说明,这里对比了使用辅助类,使用isInfoEnabled判断和不使用判断的情况,日志级别为INFO,另外再加了使用辅助类,使用isDebugEnabled判断和不使用判断的情况,都是循环输出20万次,每次的拼接在最后都加了些运算:
public class LogDemo { private static final Logger logger = LoggerFactory.getLogger(LogDemo.class); public static void main(String[] args) { Profiler.start(); Profiler.enter("Ignore"); for (int i = 0; i < 200000; i++) { LogUtil.info(logger, "test" + "test" + i + i*2); } Profiler.release(); Profiler.enter("InfoUtil"); for (int i = 0; i < 200000; i++) { LogUtil.info(logger, "test1" + "test2" + i + i*2); } Profiler.release(); Profiler.enter("isInfoEnabled"); for (int i = 0; i < 200000; i++) { if (logger.isInfoEnabled()) { logger.info("test3" + "test4" + i + i*2); } } Profiler.release(); Profiler.enter("info"); for (int i = 0; i < 200000; i++) { logger.info("test5" + "test6" + i + i*2); } Profiler.release(); Profiler.enter("DebugUtil"); for (int i = 0; i < 200000; i++) { LogUtil.debug(logger, "test7" + "test8" + i + i*2); } Profiler.release(); Profiler.enter("isDebugEnabled"); for (int i = 0; i < 200000; i++) { if (logger.isDebugEnabled()) { logger.debug("test9" + "test0" + i + i*2); } } Profiler.release(); Profiler.enter("debug"); for (int i = 0; i < 200000; i++) { logger.debug("tes1" + "tes2" + i + i*2); } Profiler.release(); Profiler.release(); System.out.println(Profiler.dump()); } }
( 说明:这里的Profiler类是个工具类,作用是记录调用的时间;代码有截取;第一个循环主要是预热一下,不在统计范围内)
经过了几次测试,结果如下:
+---29,937 [14,187ms, 24%, 24%] - isInfoEnabled
+---44,124 [13,938ms, 24%, 24%] - info
+---58,062 [31ms, 0%, 0%] - DebugUtil
+---58,093 [16ms, 0%, 0%] - isDebugEnabled
`---58,109 [46ms, 0%, 0%] - debug
+---14,968 [14,656ms, 25%, 25%] - InfoUtil
+---29,624 [14,141ms, 24%, 24%] - isInfoEnabled
+---43,765 [14,265ms, 25%, 25%] - info
+---58,030 [47ms, 0%, 0%] - DebugUtil
+---58,077 [0ms] - isDebugEnabled
`---58,077 [47ms, 0%, 0%] - debug
+---14,999 [14,922ms, 26%, 26%] - InfoUtil
+---29,921 [14,093ms, 24%, 24%] - isInfoEnabled
+---44,014 [14,219ms, 24%, 24%] - info
+---58,233 [47ms, 0%, 0%] - DebugUtil
+---58,280 [0ms] - isDebugEnabled
`---58,280 [47ms, 0%, 0%] - debug
+---14,656 [14,812ms, 26%, 26%] - InfoUtil
+---29,468 [14,344ms, 25%, 25%] - isInfoEnabled
+---43,812 [13,890ms, 24%, 24%] - info
+---57,702 [31ms, 0%, 0%] - DebugUtil
+---57,733 [16ms, 0%, 0%] - isDebugEnabled
`---57,749 [47ms, 0%, 0%] - debug
+---16,219 [16,719ms, 25%, 25%] - InfoUtil
+---32,938 [17,703ms, 27%, 27%] - isInfoEnabled
+---50,641 [15,157ms, 23%, 23%] - info
+---65,798 [47ms, 0%, 0%] - DebugUtil
+---65,845 [0ms] - isDebugEnabled
`---65,845 [47ms, 0%, 0%] - debug
(数据说明:第一列为开始计时的时间点,[]内为时间及统计,15,171ms为该阶段的具体耗时,后面的百分比是该阶段耗时在这个统计内所占的百分比)
对上述数据分析后,可以得到这样的结论:
- 日志输出前的判断确实有效,但效果甚微
- 在日志级别较低,不会输出的情况下,日志的耗时基本可以忽略 ,20万次的调用耗时在50ms内
- 在日志级别满足输出要求时,3种方法差别不大
针对第3条再做些补充说明,日志输出大的开销应该在IO上,计算应该不会很多,也不该很多,如果存在大量的运算请自己考虑下是不是有问题;既然是确认要输出的日志,那增加判断其实是种浪费,虽然这种判断的开销可以忽略。
综上所述,个人建议在日常系统中无需对日志增加isInfoEnabled判断,想通过这种处理来优化效果的作用不会很明显,还是把精力从日志移到数据库和远程调用上效果更好些。 (特殊情况下,如果在日志中有复杂的操作,可以酌情考虑,但个人不倾向于复杂的日志)
评论
完全可以啊。关键看你怎么拦截。
能给个例子看看吗?另外,还好看么?
是的,我也同意,不加这个判断,对代码的可读性很有好处,文章中我也说了,加这个很难看。
关于Log4j里是否默认有这个判断,不是每个系统都能用新版本,而且日志实现很多,也不一定直接用Log4j,比如我们在项目里用的就是公司自己封装过的。
反正我现在已经放弃了这种检查了,因为实在太难看了,影响代码阅读,性能就将就一下吧。
用AOP的方式就不难看了。
AOP可以精细到某一行代码前后了吗?仅仅是函数级别没有什么意义。
完全可以啊。关键看你怎么拦截。
是的,我也同意,不加这个判断,对代码的可读性很有好处,文章中我也说了,加这个很难看。
关于Log4j里是否默认有这个判断,不是每个系统都能用新版本,而且日志实现很多,也不一定直接用Log4j,比如我们在项目里用的就是公司自己封装过的。
反正我现在已经放弃了这种检查了,因为实在太难看了,影响代码阅读,性能就将就一下吧。
用AOP的方式就不难看了。
AOP可以精细到某一行代码前后了吗?仅仅是函数级别没有什么意义。
是的,我也同意,不加这个判断,对代码的可读性很有好处,文章中我也说了,加这个很难看。
关于Log4j里是否默认有这个判断,不是每个系统都能用新版本,而且日志实现很多,也不一定直接用Log4j,比如我们在项目里用的就是公司自己封装过的。
反正我现在已经放弃了这种检查了,因为实在太难看了,影响代码阅读,性能就将就一下吧。
用AOP的方式就不难看了。
是的,我也同意,不加这个判断,对代码的可读性很有好处,文章中我也说了,加这个很难看。
关于Log4j里是否默认有这个判断,不是每个系统都能用新版本,而且日志实现很多,也不一定直接用Log4j,比如我们在项目里用的就是公司自己封装过的。
反正我现在已经放弃了这种检查了,因为实在太难看了,影响代码阅读,性能就将就一下吧。
public void debug(Object message) { if(repository.isDisabled(Level.DEBUG_INT)) return; ...
在 Log4j 1.2.15中,其实源代码中已经判断是否开放了debug等权限。
还有一点,楼主可能没有注意,在低版本的实现中,可能没有加这个类似的判断,并且可读性更好。
是的,我也同意,不加这个判断,对代码的可读性很有好处,文章中我也说了,加这个很难看。
关于Log4j里是否默认有这个判断,不是每个系统都能用新版本,而且日志实现很多,也不一定直接用Log4j,比如我们在项目里用的就是公司自己封装过的。
public void debug(Object message) { if(repository.isDisabled(Level.DEBUG_INT)) return; ...
在 Log4j 1.2.15中,其实源代码中已经判断是否开放了debug等权限。
还有一点,楼主可能没有注意,在低版本的实现中,可能没有加这个类似的判断,并且可读性更好。
发表评论
-
那些你该了解的Spring子项目
2013-03-20 14:39 1424去年年底,Spring Framework正式发布了3.2G ... -
《实战HotSpot JVM GC》分享Slides
2012-06-22 12:09 1721前阵子在QClub上海站做了一个与JVM GC优化相关的分享, ... -
如何简单模拟Web服务
2011-03-21 18:57 2176在SOA环境中,系统不可 ... -
代码中的坏味道
2011-01-07 04:09 1369最近InfoQ上连载了郑烨 ... -
一个关于基于注解的Spring MVC的简单介绍
2009-05-26 17:52 2857前段时间给同事们做了一个关于Spring MVC的分享,简单介 ... -
实战Concurrent
2009-04-08 13:51 3898编写多线程的程序一直都是一件比较麻烦的事情,要考虑很多事情,处 ... -
关于表单防重复提交一些东东
2009-03-13 22:27 2332前阵子弄了些表单防重复提交的东西,想整理整理,免得下次要用时再 ... -
Eclipse对JDK说“不”了
2008-09-30 21:21 1959最近开始翻译Spring Recipes了,既然是讲Sprin ... -
自己写的第一段AOP代码。
2005-04-13 22:36 1573代码1:使用安全的rand() ... -
FIFO、LRU、OPT的三个简单实现
2005-04-28 16:11 31931.利用随机数产生一个指令序列,共320条指令。其地址按下述原 ... -
JMeter小实验——JSP性能简单测试
2006-04-17 16:56 2449首先要做的当然是到Apache的站点下在一个最 ... -
利用缓存提高小型站点性能
2006-04-23 16:11 1216最近结束了 ... -
都是JDBC-ODBC惹得祸
2006-09-23 11:23 1166前阵子的一个项目需要 ... -
Fedora下瞎折腾了一个半小时,还是Sun的虚拟机可靠
2007-03-23 22:00 1196今天早上跑去了网络学院做技术支持, 他们碰到的问题是一个web ... -
一个泛型Hibernate DAO实现
2007-08-06 11:58 1722自己四处参考,写写抄抄折腾出来的一个泛型Hibernate D ... -
自己出的几道关于Spring和Hibernate的面试题
2008-02-29 16:49 2483很简单的题目,随便出着玩的,如果你是高手就请直接跳过,若有雷同 ... -
Spring MVC快速上手教程
2008-04-01 22:00 3057Spring Framework可以被使用在很多场合之中,考虑 ... -
一些关于Liferay的使用心得
2008-01-07 15:58 2142Liferay是一个出色的Java开源Portal产品,其中整 ...
相关推荐
机械设计家用手摇面条机sw18可编辑非常好的设计图纸100%好用.zip
机械设计托盘库推车sw12可编辑非常好的设计图纸100%好用.zip
Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。
YOLOV5 实战对小麦叶片病害检测分类数据集,包含代码、数据集、训练好的权重参数,经测试,代码可以直接使用。 【yolov5】项目总大小:300MB 训练了10个epoch,top1准确度分别达到了0.93+。这里仅仅训练了10个epoch,网络还没收敛,加大轮次可以获取更高的网络性能 【如何训练】摆放好datasets数据,即可训练 更多yolov5改进介绍、或者如何训练,请参考: https://blog.csdn.net/qq_44886601/category_12605353.html
1.了解LED数码管的工作原理,为秒表时钟模块的实现打下基础。 LED数码管是一种常用的数字显示器件,通过控制每个LED的亮灭来显示数字。在秒表时钟模块中,我们需要利用LED数码管的这一特性,通过单片机控制数码管的显示,从而实现时钟的功能。因此,了解LED数码管的工作原理对于实现秒表时钟模块至关重要。 2.掌握51单片机与LED数码管的接口技术,是实现秒表时钟模块的关键。 51单片机是一种常用的微控制器,可以通过接口与外部设备进行通信。在秒表时钟模块中,我们需要通过单片机与LED数码管之间的接口,控制数码管的显示。因此,掌握51单片机与LED数码管的接口技术是实现秒表时钟模块的关键。在实际操作中,我们需要根据接口协议和数据传输方式,编写相应的程序来控制数码管的显示。 3.合理利用定时器/计数器,是实现秒表时钟模块的效率保障。 在秒表时钟模块中,我们需要实现计时功能,这需要使用到定时器/计数器。定时器/计数器可以用来产生计时脉冲,从而控制秒表的计时。通过合理利用定时器/计数器,可以提高秒表时钟模块的计时精度和效率。在实际操作中,我们需要根据具体的应用场景和需求,选择合适的定时器/计数器参
机械设计2T双轴变位机L型sw12非常好的设计图纸100%好用.zip
Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。
本项目基于HAL库开发,使用STM32F407作为主控芯片,串口通信过程使用了特殊的帧头帧尾,实现了通过串口触摸屏设置ADF4351输出信号频率。项目包含了陶晶弛串口屏的界面设计。
金融产品设计报告.docx
C++ 实验三 基本图形生成算法
6金融需求理论.docx
Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。
数据结构实验代码
新版广州社区智慧养老解决方案ppt
python实现python解释器 1.该python解释器是一个模拟堆栈机器的虚拟机 2.基本指令:LOAD_VALUE,将数据压入栈中,STORE_NAME,将栈顶内容存入变量,LOAD_NAME,将变量的内容压入栈中 dis是一个字节码反汇编器 3.LOAD_CONST相当于LOAD_VALUE,STORE_FAST相当于STORE_NAME 4.帧:帧包含了一段代码运行所需要的信息与上下文环境,帧在代码执行时被动态地创建与销毁,每一个帧的创建对应一次函数调用,所以每一个帧都有一个code object与其关联,同时一个code object可以拥有多个帧,因为一个函数可以递归调用自己多次 5.调用栈:每当你在当前函数内调用一次函数就在当前调用栈上压入所调用的函数的帧,在所调用函数返回时再将该帧弹出 数据栈:执行字节码操作时使用的栈 块栈:用于特定的控制流,比如循环与异常处理;每一个帧都拥有自己的数据栈与块栈
index.vue
课程大纲 真实场景专题(理论+实操) 1)产品AI创意图案例 2)产品图生成真实场景案例 3)AI产品图设计流程思路分享 二、服装模特专题(实操) 1)人台图生成AI模特案例 2)服装图换脸换背景案例 3)平面衣服上身A1模特案例 4)如何精准控制人物姿势 家居场景专题(实操)三、 1)家居产品生成AI场景 2)精准控制更换家具材质 3)家居装修风格快速切换
App商业化的平衡之道:左手营收,右手用户,如何找到平衡点?.docx
设计沉思录 二手车工具产品设计.docx
文件预览kkFileView安装包下载【win+Linux】4.0版本