实际场景:
1.Server接收客户端请求
2.去数据库中获取数据(一般会有I/O操作)
3.得到数据后发送回复,响应客户端请求
具体实现:
在上面的三个步骤中,第二步中的I/O操作是很浪费时间的,跟其它步骤不在一个时间数量级上。
(1)如果采用单线程实现,那么CPU在第二步的时候需要一直等待I/O结果返回,这段时间CPU什么都做不了。
(2)如果采用多线程实现,我们可以至少设置两个线程,一个线程用来处理接收客户端请求并开启I/O操作,一个线程用来向客户端发送回复操作。
结果分析:多线程和单线程相比,省去了等待I/O操作的时间,但是多了CPU上下文切换。I/O操作远比CPU上下文切换要耗费时间,因此在有I/O操作的情况下,使用多线程的性能会更高。
一般我们的程序都会穿插许多I/O操作,所以大多情况下使用多线程会更好。
进阶内容1:那什么时候使用单线程呢?
答:在I/O操作很少或者没有的情况下,可以使用单线程。
背景介绍:例如Redis,就是使用单线程。因为他的数据存储都是基于内存的,没有I/O操作,因此他并不会在获取数据的时候耗费性能。相反地,如果说用多线程实现上述操作,redis还会多出许多CPU上下文切换的时间,在没有I/O操作的情况下,这些CPU上下文切换的操作就是最损耗性能的操作。
进阶内容2:优化Redis
背景:有时候我们比操作系统更懂我们的程序,所以我们不能任由操作系统负载均衡
在多核CPU下,redis运行时是会随机使用CPU内核的,这样就会带来CPU上下文切换。所以我们可以通过绑定redis到一个特定的CPU内核中,这样就不会带来CPU上下文切换。在Linux中,可以使用taskset将特定进程绑定到特定CPU中。