进程、线程、协程

Posted by xiezg247 on March 11, 2016

高并发/高性能 (进程/线程/协程)

进程线程协程之间的区别和联系

先来看一个例子:

一个蓄水池,是1m1m1m=1立方米大小,有一个出水口,出水口每秒钟流出0.1立方米,那么这个蓄水池的并发量是1立方米,出水速度是0.1立方米/秒。

如果增加一个出水口,都是每秒钟流出0.1立方米,那么这个蓄水池的并发量没变,但是出水速度变成了0.2立方米/秒。

同理,增大了出水口,蓄水池的出水速度也变快了。

上面我们很容易知道,并发量是一个容量的概念,性能就是出水速度,而且有下面这些结果。

1 增大蓄水池的长宽高,可以增加并发能力。

2 出水口如果扩大了出口大小,则可以提高出水的速度,也就是性能提高了。

3 增加出水口的数量,则是增加了并行处理的能力,同样可以提高性能。

那么对照我们计算机中,我们的系统中,是怎么样的结果呢?

1 增加服务器的内存大小,可以增加并发量。因为内存增加了,就可以开更多的进程,更多的线程,也可以扩大任务队列的大小。

2 提高cpu的主频速度,优化程序,可以提高性能。cpu更快了,程序优化的更好了,处理单个任务的时间也就更短了。

3 增加多核甚至分布式服务器数量,也可以提高性能,同时提高并发量。

看以下并发模型

process : thread : task

1
2
3
4
5
6
7
- 1:1:1 -> 单进程,单线程,单任务。例如阻塞型echo server Redis网络模型
- N:1:N -> 多进程,单线程,多任务。进程池
- 1:N:N -> 单进程,多线程,多任务。线程池
- 1:1:N -> 单进程,单线程,多任务。Python中的协程实现
- 1:M:N -> 单进程,多线程,多任务。Golang的GMP模型 Memcached
- M:N:Z -> 多进程,多线程,多任务。Nginx的多worker,每个worker多线程,每个线程+epoll处理多请求
- ...

多进程和多线程的模式,不仅是内存开销巨大,而且在数量不断增加的情况下,对CPU的压力也是非常巨大,这也是为什么这类系统在并发量大的情况下会很不稳定,甚至宕机。

上面假设中计算出来的数据,都是静态的容量,如果所有任务都不处理,那么肯定都是会很快就被撑爆。

所以要达到更高的并发量,就需要有更快的处理速度,即做好性能优化。

下面,再来做一个假设。

我们现在有一台服务器,配置是8核16G内存。

如果我们的应用是计算密集型,纯运算的系统,如:数据索引查询、排序等操作。

而且还要假设,这个应用在多核并行运算时不存在锁竞争的情况(只读)。

qps=1000ms/单个请求耗时*8

如果单个请求(任务)耗时100ms,那么我们可以计算出来

qps=1000ms/100ms*8=80个/秒

如果我们优化处理的算法,单个请求耗时降低到10ms,那么

qps=1000ms/10ms*8=800个/秒

如果可以继续优化,将单个请求耗时降低到1ms,那么

qps就可以达到更高的8k

上面的情况和优化的效果理解起来应该很容易,因为对服务器资源的依赖更多是CPU的运算能力和数量。

在实际的互联网应用中,系统更多是依赖mysql,redis,rest api或者微服务,属于IO密集型。

按照上面的计算方式,可能就不太准确了,因为cpu是有富余的。

在IO阻塞的时候,开启更多任务的方式当然有上面多进程、多线程、多协程和队列的方式来实现。

而且也是有效的更好的利用服务器资源的方法,可以达到更高的并发量,毕竟我们把大部分的运算放到了应用外部的mysql,redis,rest api等服务。

到此为止,我们已经知道并发量、性能优化跟服务器资源(服务器数量,cpu,内存)的关系,也知道性能优化对并发量的影响。

免创建、销毁、维护太多进程、线程,导致操作系统浪费资源在调度上;

避免分布式系统中多服务器的关联,比如:依赖同一个mysql,程序逻辑中使用分布式锁,导致瓶颈在mysql,分布式又变成串行化运算。

上面说了要避免的地方,要具体怎么来避免,到具体的业务场景就需要具体分析了。

而且有些时候,为了业务功能,或者其它方面的需求,比如:可用性、伸缩性、扩展性、安全性,不得不牺牲掉一部分性能。

最后,做一个总结:

并发量,是一个容量的概念,服务可以接受的最大任务数量,动态的看待它,还需要把性能考虑进去。

性能,是一个速度的概念,单位时间内可以处理的任务数量。

高并发和高性能是紧密相关的,提高应用的性能,是肯定可以提高系统的并发能力的。

应用性能优化的时候,对于计算密集型和IO密集型还是有很大差别,需要分开来考虑。

增加服务器资源(CPU、内存、服务器数量),绝大部分时候是可以提高应用的并发能力和性能(前提是应用能够支持多任务并行计算,多服务器分布式计算才行),但也是要避免其中的一些问题,才可以更好的更有效率的利用服务器资源。