本文仅代表带个人观点及理解,本人只是一个编程小菜鸟,如果有不对的地方。请大佬轻喷!
前言:很多程序员认为像“并发”这么高级的内容离自己很遥远甚至是毫无关系。当我听到这个想法的时候,说实话我很惊讶。实际上并发处理这个词语是与程序员日常工作中所编写的程序息息相关的。试想一下,如果一个程序原本响应速度平均1秒(举例而已,大佬们不要认真)。而由于工作中不注重代码规范,性能等问题。导致响应速度变成了2秒,那么您整体的并发处理还能保持原有的速度吗?要知道每个应用程序池的线程数量是有限的如果单个线程响应速度变慢了一倍,不仅延长了后续其他列队的处理。还有可能会导致列队上限从而引发响应超时,无法访问等问题。(不清楚ISS的可以查看 《关于并发你真的了解吗?(一)》 http://www.cnblogs.com/xinwuhen/p/7049093.html)而这个效率最少降低了一倍以上,一倍是什么概念。这导致公司为了处理高并发问题可能要再投入一倍的财力来搭建机房,这导致原本可以处理的并发数量。“现在”变成了各种访问超时,无法访问!本文将为您介绍日常工作中如何优化性能和日常编程过程中"如何提高并发处理效率"(提高响应速度间接等于提高并发处理能力嘛)。
1.有一些童鞋喜欢在网上扒一些插件,自定义控件等使用。并且一般都不会查看插件,控件源码。现在的插件,控件很垃圾,不但占服务器资源,而且会使网站运行变慢。去掉垃圾的插件,用标准版!或者自己定义高性能控件。
2.页面嵌套,在一个页面中显示另一个页面的内容。用户的一次访问对服务器来说却是两次或以上。尽量不要采用框架的形式制作页面!
3.页面静态化- 用户可以直接获取页面,不用走那么多流程,比较适用于页面不频繁更新。
4.使用缓存- 第一次获取数据从数据库准提取,然后保存在缓存中,以后就可以直接从缓存提取数据。不过需要有机制维持缓存和数据库的一致性。
5.您的网站图片,文件等资源被人盗链!要防止盗连情况的发生!
6.批量读取 - 高并发情况下,可以把多个请求的查询合并到一次进行,以减少数据库的访问次数
7.延迟修改 - 高并发情况下,可以把多次修改请求,先保存在缓存中,然后定时将缓存中的数据保存到数据库中,风险是可能会断电丢失缓存中的数据
8.使用索引 - 索引可以看作是特殊的缓存,尽量使用索引就要求where字句中精确的给出索引列的值。
9.使用储存过程-那些处理一次请求需要多次访问数据库的操作,可以把操作整合到储存过程,这样只要一次数据库访问就可以了。另外存储过程也节省了预编译的过程,进而打到节省时间的作用。使用存储过程来代替SQL语句查询,还可以在编写存储过程中加入一定的逻辑,从而提高程序的安全性。
10.使用性能较高的SQL语句,很多童鞋在写SQL语句的时候图方便。直接写 Select *或者Count(*)等语句,但是你可知道Select *和Select 列明 在大数据情况下会产生几倍的差距。而Count(1)和Count(*)的差距更是无法想象的。
11.养成检查代码的好习惯,避免因代码质量造成宕机。
12.提高代码质量
请看下面的两段代码:
代码1: ClassTest CT; for(int i = 0; i < 100; ++i) { CT = new Test() ; //do something } 代码2: for(int i = 0; i < 100; ++i) { ClassTest CT =new Test() ; ; //do something } 你会觉得哪段代码的运行效率较高呢?其实这种情况下,哪段代码的效率更高是不确定的,或者说是由这个类ClassTest本向决定的,分析如下: 对于代码1:需要调用ClassTest的构造函数100次赋值操作100次;对于代码2:需要声明变量100次,构造函数100次。 如果调用赋值操作函数的开销比声明变量的总开销小,则第一种效率高,否则第二种的效率高。 当然循环内定义,还是循环外定义对象也需要根据自身需求情况来判断,不要发生本末倒置的情况哦。 现在请看下面的两段代码, 代码1: for(int i = 0; i < n; ++i) { fun1(); fun2(); } 代码2: for(int i = 0; i < n; ++i) { fun1(); } for(int i = 0; i < n; ++i) { fun2(); } 注:这里的fun1()和fun2()是没有关联的,即两段代码所产生的结果是一样的。 以代码的层面上来看,似乎是代码1的效率更高,因为毕竟代码1少了n次的自加运算和判断,毕竟自加运算和判断也是需要时间的。但是现实真的是这样吗? 这就要看fun1和fun2这两个函数的规模(或复杂性)了,如果这多个函数的代码语句很少,则代码1的运行效率高一些,但是若fun1和fun2的语句有很多,规模较大,则代码2的运行效率会比代码1显著高得多。可能你不明白这是为什么,要说是为什么这要由计算机的硬件说起。 由于CPU只能从内存在读取数据,而CPU的运算速度远远大于内存,所以为了提高程序的运行速度有效地利用CPU的能力,在内存与CPU之间有一个叫Cache的存储器,它的速度接近CPU。而Cache中的数据是从内存中加载而来的,这个过程需要访问内存,速度较慢。 这里先说说Cache的设计原理,就是时间局部性和空间局部性。时间局部性是指如果一个存储单元被访问,则可能该单元会很快被再次访问,这是因为程序存在着循环。空间局部性是指如果一个储存单元被访问,则该单元邻近的单元也可能很快被访问,这是因为程序中大部分指令是顺序存储、顺序执行的,数据也一般也是以向量、数组、树、表等形式簇聚在一起的。 看到这里你可能已经明白其中的原因了。没错,就是这样!如果fun1和fun2的代码量很大,例如都大于Cache的容量,则在代码1中,就不能充分利用Cache了(由时间局部性和空间局部性可知),因为每循环一次,都要把Cache中的内容踢出,重新从内存中加载另一个函数的代码指令和数据,而代码2则更很好地利用了Cache,利用两个循环语句,每个循环所用到的数据几乎都已加载到Cache中,每次循环都可从Cache中读写数据,访问内存较少,速度较快,理论上来说只需要完全踢出fun1的数据1次即可相信对于一些初入编程的童鞋来说并不清楚struct或者从未使用甚至没有见过。如下代码,可自行拷贝使用一下。
struct MyStructure { public string Name; public string Surname; } class MyClass { public string Name; public string Surname; }
class Program { static void Main(string[] args) { MyStructure [] objStruct =new MyStructure[1000]; MyClass[] objClass = new MyClass[1000]; Stopwatch sw = new Stopwatch(); sw.Start(); for (int i = 0; i < 1000; ++i) { objStruct[i] = newMyStructure(); objStruct[i].Name = "Sourav"; objStruct[i].Surname = "Kayal"; } sw.Stop(); Console.WriteLine("For Structure:- "+ sw.ElapsedTicks); sw.Restart(); for (int i = 0; i < 1000; ++i) { objClass[i] = newMyClass(); objClass[i].Name = "Sourav"; objClass[i].Surname = "Kayal"; } sw.Stop(); Console.WriteLine("For Class:- " + sw.ElapsedTicks); Console.ReadLine(); }
我的运行结果为(可自行尝试体会):
For Structure:- 46
For Class:- 531
相信性能差距已经一目了然了。
本文版权归作者 心灬无痕(博文地址:http://www.cnblogs.com/xinwuhen/)所有,欢迎转载和商用,请在文章页面明显位置给出原文链接并保留此段声明,否则保留追究法律责任的权利,其他事项,可留言咨询。
转载于:https://www.cnblogs.com/xinwuhen/p/7065960.html
