浅析Linux线程池及其实现

         许多服务器应用程序,如Web服务器,数据库服务器等都面临着处理众多客户端发起的请求,这些请求往往都是短暂的、大量的。如果采用为每个到达的请求创建一个新线程来响应客户端请求的话,至少存在以下两个缺点:

         其一,为每个请求都创建一个线程的开销会非常大;其二,除了创建和销毁线程的开销外,大量活动线程还会消耗系统资源,导致系统内存不足或由于内存消耗过多而导致系统崩溃。

         线程池为上述提及的线程生命周期开销问题及系统资源消耗问题提供了解决方案。

1.概念

         在计算机程序设计中,线程池(thread pool)[1]是一种用来实现计算机程序并发性编程的软件设计模式。一个线程池维护着多个线程,等待监控程序分配并发执行的任务。通过维护线程池,该模型可以避免线程的频繁创建和销毁从而提高了程序的性能。

         为线程执行调度任务的一种常见方法是使用同步队列,通常称之为任务队列(task queue)[1],线程池将任务队列中等待的任务移除并交给空闲的线程进行相应的处理。如图1-1所示:

Thread_pool图1-1

2.性能

         线程池的大小是为执行任务而保留的线程数量,它通常是应用程序的可调参数,经过调整以优化程序性能。

         相比于为每个任务创建一个新线程,使用线程池的开销要远远小于前者,这会为程序带来更好的性能和稳定性。因为,创建和销毁一个线程及其相关资源是一个代价高昂的过程。但是,线程池中的线程的数量也不是越多越好,线程过多的话会不仅会浪费内存,并且在线程之间的上下文切换也会导致性能的下降。

         在应用程序的生命周期中,我们还可以根据任务队列中的等待任务的数量动态的调整线程池中线程的数量(如文章最后的示例所示)。例如,对一个web服务器而言,当有大量的web请求到来时,web服务器可以添加线程,而当这些请求逐渐减少时,web服务器也可以销毁部分线程。而至于添加或销毁多少线程,都与系统的性能息息相关,因此我们需要知道:
(1)创建太多线程不仅会浪费系统资源,还会浪费时间;
(2)同理,盲目销毁太多的线程也不可取;
(3)创建线程的速度过慢的话可能会导致客户端性能低下(等待时间长);
(4)销毁线程的速度过慢的话可能会导致系统资源的枯竭。

         因此,线程的多少直接影响到程序的性能,一个线程池中究竟需要创建多少个线程取决于多个方面,如CPU、内存以及业务逻辑等。

3.工作队列

         在查阅相关资料之后,本人还是没能找到线程池和工作队列两个术语之间区别的权威说明。其中,参考文献[3]中指出,“The work queue is a simple and elegant type of thread pool that creates requested number of threads at its creation and manages a queue of different work items that implement the specific tasks, where each work item in his turn gets a thread that works and processes it.”

         结合查阅的资料,我个人所倾向的理解是:线程池是一种软件设计模式,而工作队列则是这种模式的一个具体实现。

4.示例

         当创建工作队列时,可以指定需要的最大并发级别。我们可以通过“工作量”的大小,适当的增加或减少线程。并且,如果一个线程在经过一定的时间后仍然没有获得“工作”,那么我们可以将其销毁以达到释放资源的目的。

(1)工作队列

         work_queue.h及work_queue.c两个文件包含了工作队列的具体实现,并且我在代码中加了较为详细的注释,此处不再赘述。

work_queue.h源码如下:

         work_queue.c源码如下:

(2)实例

         main.c实例中,我们初始化一个工作队列,并向工作队列中添加10个任务,main.c源码如下:

(3)编译、运行:

 

参考:
[1] https://en.wikipedia.org/wiki/Thread_pool
[2] https://www.ibm.com/developerworks/java/library/j-jtp0730/index.html
[3] https://www.codeproject.com/Articles/3607/Work-Queue
[4] David R.Butenhof. POSIX多线程程序设计

发表评论

电子邮件地址不会被公开。 必填项已用*标注