• 内存池、线程池与进程池


    1、池的概念

      一般来说,服务器的硬件资源相对充裕,很多时候我们使用以空间换时间的方法来提高服务器的性能,不惜浪费更多的空间以换取服务器运行效率。具体做法是提前保存大量的资源,以备不时之需以及重复使用。这就是池的概念。池是一组资源的集合,这组资源在服务器启动之初就已经被创建并初始化,这称为静态资源分配。当服务器正式运行,开始处理客户请求的时候,如果需要相关的资源,服务器就可以直接从池中获取,无需动态分配。动态分配即由系统实时分配资源,而右系统调用分配资源都是很耗时的。所以直接从池中取得资源比动态分配资源的效率更高。而且当服务器使用完资源后,可以直接放回资源池无需执行系统调用来释放资源。池相当于服务器系统调用管理资源,避免了服务器对内核的频繁访问,从而提高服务器性能。

      由于在实际应用当中,分配内存、创建进程、线程都会设计到一些系统调用,系统调用需要程序从用户态切换到内核态,是非常耗时的操作。因此,当程序中需要频繁的进行内存申请释放,进程、线程创建销毁等操作时,通常会使用内存池、进程池、线程池技术来提升程序的性能。

    2、内存池

      在C/C++中我们一般运用new或malloc向申请系统分配资源,由于所申请内存块的大小不定,当频繁使用时会造成大量的内存碎片,不仅耗时,而且大量内存碎片出现的结果是出现系统明明有大量资源而无法使用。如下图:

    如果我们再需要30字节资源的话,对于左边有内存碎片问题的情况是无法得到30字节完整内存的,然而内存总共确实还有多余30字节的空间,这就是内存碎片问题。

      内存池是指程序预先从操作系统申请一块足够大内存,此后,当程序中需要申请内存的时候,不是直接向操作系统申请,而是直接从内存池中获取;同理,当程序释放内存的时候,并不真正将内存返回给操作系统,而是返回内存池。当程序退出(或者特定时间)时,内存池才将之前申请的真正内存释放。这样做的一个显著优点是尽量避免了内存碎片问题,还使得内存分配效率得到提升。

    3、进程池与线程池

    这两个概念相似,这里以线程池为例介绍。

    为什么要提出进程池线程池,因为它们可以解决服务器动态创建子进程(或子线程)的以下缺点:

    (1)动态创建进程(或线程)比较耗费时间,这将导致较慢的客户响应。

    (2) 动态创建进程(或线程)将导致系统上产生大垃的细微进程(或线程)。进程(或线程)间的切换将消耗大量 CPU 时间。

    (3)动态创建的子进程是当前进程的完整映像。当前进程必须递慎地理其分配的文件描述符和堆内存等系统资源,否则子进程可能复制这些资源,从而使系统的可用资源急剧下降,进而影响服务器的性能。

      而进程池解决了以上问题。进程池是由服务器预先创建的一组子进程,这些子进程的数目在 3~10 个之间(当然这只是典型情况)。线程池中的线程数量应该和 CPU 数量差不多。进程池中的所有子进程都运行着相同的代码,并具有相同的属性,比如优先级、 PGID 等。因为进程池在服务器启动之初就创建好了,所以每个子进程都相对 干净 ” ,即它们没有打开不必要的文件描述符(从父进程继承而来),也不会错误地使用大块的堆内存(从父进程复制得到)。当有新的任务来到时,主进程将通过某种方式选择进程池中的某一个子进程来为之服务。相比于动态创建子进程,选择一个已经存在的子进程的代价显得小得多。至于主进程选择哪个子进程来为新任务服务,则有两种方法:

    (1)主进程使用某种算法来主动选择子进程。最简单、最常用的算法是随机算法和 Round Robin 算法(轮流选取)。

    (2)主进程和所有子进程通过一个共享的工作队列来同步,子进程都睡眠在该工作队列上。当有新的任务到来时,主进程将任务添加到工作队列中。这将唤醒正在等待任务的子进程,不过只有一个子进程将获得新任务的“接管权”,它可以从工作队列中取出任务并执行之,而其他子进程将继续睡眠在工作队列上。

      当选择好子进程后,主进程还需要使用某种通知机制来告诉目标子进程有新任务需要处理,并传递必要的数据。最简单的方式是,在父进程和子进程之间预先建立好一条管道,然后通过管道来实现所有的进程间通信。在父线程和子线程之间传递数据就要简单得多,因为我们可以把这些数据定义为全局,那么它们本身就是被所有线程共享的。线程池主要用于:

    (1)需要大量的线程来完成任务,且完成任务的时间比较短。 比如WEB服务器完成网页请求这样的任务,使用线程池技术是非常合适的。因为单个任务小,而任务数量巨大。但对于长时间的任务,比如一个Telnet连接请求,线程池的优点就不明显了。因为Telnet会话时间比线程的创建时间大多了。

    (2)对性能要求苛刻的应用,比如要求服务器迅速响应客户请求。

    (3)接受突发性的大量请求,但不至于使服务器因此产生大量线程的应用。

     参考:《Linux高性能服务器

  • 相关阅读:
    Centos7下rc.local文件开机不执行…
    Centos7添加密码安全策略
    Java8 时间日期类操作
    XML配置spring session jdbc实现session共享
    Spring Boot 2.x以后static下面的静态资源被拦截
    外观模式
    组合设计模式
    Java线程池源码解析
    观察者模式
    Java使用POI解析Excel表格
  • 原文地址:https://www.cnblogs.com/33debug/p/7372099.html
Copyright © 2020-2023  润新知