性能优化第1节课

一、第1节课

今日课堂目标

数据库SQL语句写的不够好,硬件不行了,都是我们的揣测。在我们没有进行排查之前,任何结论都是不可靠的。

1000条到100万条之间,问题不在SQL语句,也不在服务器环境,而在代码处理的逻辑上。

先从文件中读取1条数据,放在链表,接着在数据库中持久化这条数据。

问题出现在哪?出现在链表中了。如果放在链表中100万条数据,那么,每次向数据库中放入一条数据,都要遍历这100万条数据。

主要原因:应用程序的设计导致性能变差。

要想做好性能优化,需要了解一些性能优化的基础理论。

1、算法对性能的影响

(1)数组,时间复杂度O(n),100完个数据进行处理。

优点:适合循环处理,适合按顺序存放数据、查找数据。

缺点:如果事先不知道数组长度的话,那么就是占用过多空间,要么就是空间不够。插入数据也不方便。

 

(2)链表,像链条一样的数据结构。数据以及下一个箱子(节点)的位置或地址。复杂度O(n)。

访问链表中某一个节点A的下一个。

优点:灵活。插入数据,在插入数据后,把链表连起来就可以。

缺点:不能使用随机访问,只能走一遍。只要知道地址就可以随机访问。

 

(3)树(二叉树、N叉树、B树)

B树:尽量保持各分支平衡的多叉树。只在树的叶子节点存放数据。

在开发中,主要处理的数据是查询。查找相应的数据。树结构就是为了方便查找而创造出来的。

在树中放1000条数据和放100万个数据,层级高度,只差30倍。

访问多少次后能找到目标数据,1000个的话是32此,100万个数据就是1000此。

优点:可以不同检查无关的数据,查找树右边的话,左边的就可以不看了。范围会逐渐缩小。

缺点:数据更新不方便。如果总是放入相同的数据,会导致某一个特定位置的分支不断延伸,这样就不能发挥它的性能优势了。

 

(4)散列算法

使用这个算法,只需要一次计算就可以找出数据。散列算法的复杂度:O(1)

散列计算 用的是取余,余数。

1、5、9、13、16、27、38、102。

对这些数据进行取余,把这些数据当作下标来使用。

10个空间的数组,用10求余。依次下去,就可以知道0~9的下标。

18,28,用10求余得到8。该值称为散列值。

优点:不论数据量怎么增加,都可以在一定时间内完成查找和储存;有消除不平衡性的效果(针对相同的数据)。

缺点:散列值相同。

 

(5)队列

适用于按顺序来处理工作。

优点:[1]当有大量处理涌入时,可以先将其放入队列,按顺序处理。尤其访问人气很高的网站,需要一段时间才出现,这是因为放入到了队列里来处理。[2]用于多个系统之间的连接点,还可以作为缓冲。这种方式不适用于那些需要实时响应的数据,为了处理结果,需要重新访问你一次。这也是它的缺点。

 

明白数据结构与算法的优缺点后,在做项目的时候,就知道在什么情况下需要用哪种算法了。

在性能优化上,数据结构与算法是非常重要的基础知识。

2、缓存对性能的作用

CPU中也有缓存。缓存指的是为了提高性能而保存的东西。为了提高性能,把这些东西保存在比较近的地方。

缓存方式有两种:回写、直写。

回写:更新数据的时候,要考虑是否需要更新缓存。先更新缓存内的数据,再更新实际存放数据的地方。

回写的优点:不用等待写入数据实际存放的地方,所以速度很快。

回写的缺点:如果缓存中的数据丢失的话,那么,实际保存数据的地方内的数据就是旧的。

 

如果一定要确保再数据实际存放的地方保存,再更新缓存,就需要用直写的方式。

直写的优点:可以确切的保证数据的更新。

直写的缺点:速度慢。

 

3、锁

数据库中的锁:行锁、表锁。

编程语言中的锁、CPU命令级别的锁、数据库内部也有锁。

锁是在并行处理的情况下所必须的机制。

链表结构中,在1和4之间插入数据2,同时,另一个程序,想在1和4之间插入3。那么出现的结果就是,链表结构会被破坏掉。为了防止这种情况,在更新链表的时候,让别的程序等待。

锁,就是在某个处理进行期间起到保护作用的机制,是为了防止别的处理侵入。

 

如果你已经知道只有一个线程进行操作,那么不用锁也可以。

.NET是线程安全,是因为它的底层都有锁。

 

读取的时候也需要加锁。在读取一个值以后,同时有另外一个程序对这个值进行更新了。那么,读取的值就不正确了。这属于不可重复读取。

锁在等待的时候发生了什么事情?在性能测试和生产环境中,会出现多个请求同时涌入,那么,等待锁释放,就排起了一个长队,等待时间会以指数级别增长。

如何解决这个等待的问题?锁在进行保护的过程中,只要处理没有完成,就不能释放锁。最基本的解决办法就是“让受保护的处理尽快完成”。

如果是表锁,那么,就要让SQL尽快完成。减少占有锁的时间。

分割锁,把表锁换成行锁。这就是把锁分割了。

4、响应与吞吐

考虑性能的时候,还有两个重要的概念。响应与吞吐。

响应表示的是应答的快慢。

吞吐表示的是处理数量的多少。

响应就像是几乎装载不了什么东西,但速度飞快的赛车。

吞吐就像是速度很慢,但能装载大量货物的卡车。

 

一个人搬运一次货物需要10秒,2个人搬运一次货物仍然需要10秒。时间还是10秒,但是工作量增加了。在这里,工作量就是吞吐,时间就是响应。

 

在实际的环境中,有的系统是偏重响应的,有的系统是偏重于吞吐。偏重于响应是万金油的做法,响应变快的话,一般来说吞吐也会变大。但是就像CPU的时钟频率一样,和磁盘的IO都会有极限。物理上的增速是有限度的,硬件不能无限的提速。那么,这时,就需要偏重吞吐的系统。

 

热门的网站和APP,即使访问很集中,响应也不会变慢。这种擅长处理高并发的系统,是偏吞吐的系统。

 

PC和服务器比较,CPU的时钟频率并没有很大的差异,但是,价格相差上百倍。这样的原因,很简单。服务器为了能够支撑高并发,进行了优化。

所以,在考虑的时候,要明白你的系统是偏向于响应,还是偏重于吞吐。

 

5、性能分析工具

性能必须是可以测量的。如果不知道问题原因,就没办法解决。换句话说,性能问题的处理和性能调优都是从正确的测量开始的。

 

(1)VS中,帮助我们分析应用程序中的性能问题。

VS性能探查器,简单的测试是可以做到的。

对单个类进行分析。使用,在Main函数的开始、结尾设置断点,Deug版,(测试——>窗口——>诊断工具),启动调试。在诊断工具中,CPU使用率中有个“记录CPU配置文件”。

对整个项目进行分析。Release版。测试——>性能探查器,选择CPU使用率。可以诊断当前系统整体进行探查。外部代码:是系统代码,可以略过。企业版和专业版有。

 

(2)dotTrace,它是JetBrains出的一款.NET性能分析工具。收费。可以在不同维度进行分析,也支持.NET Core。有2种启动方式,四种分析模式。如果安装了的话,在扩展中可以找到。

四种分析模式:Sampling、Tracing(常用)、Line-by-Line、Timeline

Sampling:分析模式很快,分析的是总体性能,不够精确,可能会丢失一些数据。

Tracing:可以准确的测量方法被调用的数据(次数、时间)。

Line-by-Line:收集每一条语句的执行时间,但是也慢。使用范围:知道出现性能问题的大概位置在哪里

Timeline:少于10毫秒的方法就无法抓取到。

 

使用Tracing模式后,在出现的分析报告中,主要看User code。

 

VS性能分析与dotTrace性能分析,dotTrace看到的东西多,但不够直观。VS则相反。

 

性能探查器,就可以直接运行WEB项目。比如你去访问你一个接口,就会被性能探查器捕捉,停止项目。性能分析数据就会出结果了。

6、性能测试工具

Benchmark,是开源的.NET程序性能测试的组件。在NuGet中直接安装。

对方法进行基准测试。

Benchmark测试步骤:

(1)确定要运行几次

(2)评估Benchmark这个组建带来的额外开销

(3)热身

(4)测试

(5)测试结果(减去Benchmark测试带来的额外开销)

(6)生成报告

 

在方法上,表明[Benchmark]特性,直接运行即可。看标红部分即可。

 

性能优化,没有一个统一标准,有的只是一个理论或方法。

posted @ 2020-03-31 21:57  揽月2020  阅读(157)  评论(0编辑  收藏  举报