Hi!这是我的青训营笔记的第4篇。本节笔记中,我们将分析传统IO密集型程序所遇到的IO瓶颈,并分析Linux系统提供的IO多路复用、MMAP等技术是如何缓解这些瓶颈的。
首先,我们从一个传统IO密集型程序的瓶颈说起。所谓IO密集型,就是在运行这些程序时,CPU大部分时间都在等待内存、硬盘或网络的读写操作,CPU本身的运算负载并不高。IO密集型程序的典型代表就是各种Web服务器应用。它们并不处理复杂计算,大部分时间都在网络间接受和发送数据。
想要优化这些程序,我们需要从产生问题的原因出发。IO密集型程序性能低下的原因之一是CPU大部分时间都在等待IO,而我们想充分利用空转的CPU性能。传统的IO密集型程序对CPU性能的利用主要体现在多线程/多进程上。
传统IO密集型程序的多线程应用
这种方法是出于最大化利用CPU时间的,采用的是由操作系统提供的基础设施——线程。我们知道,单核CPU在同一时刻只能做一件事情,一种解决方法是对CPU进行时分复用。在操作系统中,这种时分复用一般用线程之间的调度来体现。通过这种方法,不同的线程可以逻辑上并发执行,当一个线程上的程序在等待IO时,另外一个需要CPU的线程便可以占据CPU进行处理操作。这样便实现了CPU性能的最大化。
但是,这样的操作在现代IO密集型程序中还是遇到了瓶颈:
- 线程和进程具有创建成本
- CPU在不同的线程之间的上下文切换成本
- 多线程的资源竞争:线程切换保证了每个线程都会得到一些CPU资源,但是不能保证每个线程获得足够的CPU资源
我们观察到,传统IO密集型程序的多线程操作是将IO操作分布到了多个线程中执行,而正是这些线程之间的切换造成了性能瓶颈,那么,有没有一种方法将若干个线程等待的IO操作集中到一个线程上执行呢?这就要引入由操作系统提供的IO复用技术了。
IO复用技术加速IO密集型程序
Linux系统中提供了IO多路复用技术来实现单线程中同时处理多路IO。首先都会对一组文件描述符进行相关事件的注册,然后阻塞等待某些事件的发生或者等待超时。IO多路复用可以在单线程中关注多个文件描述符,从而缓解性能瓶颈。