Linux中的多进程和多线程

2017年03月16日 shenbowei

相关概念

进程

UNIX标准把进程定义为:“一个其中运行着一个或者多个线程的地址空间和这些线程所需要的系统资源”。 像Linux这样的多任务操作系统可以同时运行多个程序。每个运行着的程序实例就构成一个进程。 正在运行的程序或者进程由程序代码、数据、变量(占用着系统内存)、打开的文件(文件描述符)和环境组成。 一般来说,Linux系统会在进程之间共享程序代码和系统函数库,所以在任何时刻内存中都只有代码的一份副本。

线程

在一个程序(进程)中的多个执行路线就叫做线程。更准确的定义是:线程是一个进程内部的一个控制序列。 虽然Linux和许多其他的操作系统一样,都擅长同时运行多个进程,但是所有程序在执行时都是作为一个单独的进程。 事实上,所有的进程都至少有一个执行线程。

多进程 vs 多线程

  • 当进程执行fork调用时,将创建出该进程的一份新副本。这个新进程拥有自己的变量和PID,它的时间调度也是独立的, 它的执行(通常)几乎完全独立于父进程。

  • 当在进程中创建一个新线程时,新的执行线程将拥有自己的栈(因此也有自己的局部变量), 但与它的创建者共享全局变量、文件描述符、信号处理函数和当前目录状态。

正因为如此,新线程的创建代价要比新进程小得多。但是,在调试和可靠性方面,进程要由于线程。

下面,我们通过几组实验来比较下多进程和多线程的执行效率。

实验

代码已经放到了github:process-vs-thread

实验环境:

centos虚拟机,虚拟机内存分配为2GB,cpu为Intel(R) Core(TM) i7-4710MQ CPU @ 2.50GHz,分配给虚拟机一个cpu核心。 系统内核信息为:

$ cat /proc/version 
Linux version 3.10.0-327.el7.x86_64 (builder@kbuilder.dev.centos.org) (gcc version 4.8.3 20140911 (Red Hat 4.8.3-9) (GCC) ) #1 SMP Thu Nov 19 22:10:57 UTC 2015

实验结果

  • 进程、线程数:255 打印次数:50 输出:“测试程序”
    多进程时间: 0m0.518s 0m0.612s 0m0.300s 0m0.375s 0m0.408s 平均=0.4426s
    多线程时间: 0m0.105s 0m0.321s 0m0.369s 0m0.258s 0m0.144s 平均=0.2394s
  • 进程、线程数:255 打印次数:5000 输出:“测试程序”
    多进程时间: 0m30.123s 0m27.487s 0m18.338s 0m18.876s 0m12.297s 平均=21.4242s
    多线程时间: 0m29.009s 0m25.233s 0m20.883s 0m14.696s 0m9.197s 平均=19.8036s
  • 进程、线程数:1000 打印次数:5000 输出:“测试程序”
    多进程时间: 1m4.242s 0m42.054s 0m55.014s 0m34.168s 0m35.886s 平均=46.2728s
    多线程时间: 1m1.503s 0m54.809s 0m53.858s 0m41.939s 0m29.984s 平均=48.4186s
  • 进程、线程数:1000 打印次数:500 输出:1KB的文本文件
    多进程时间: 3m39.946s 3m51.776s 3m13.014s 3m39.323s 3m37.750s 平均=3m36.3618s
    多线程时间: 3m35.358s 3m33.358s 3m19.832s 3m41.358s 3m42.176s 平均=3m34.4164s

目前只做了上述四组实验,我也尝试了改变分配的cpu核心数,实验结果差不多。 结果和预想差不多:

  • 当进程/线程数目不多,且处理任务并不重时,多线程由于其创建代价小,所以相对于多进程多线程的优势会比较明显些。

  • 而随着进程、线程数目的增多,或者处理任务的加重时,多进程多线程的差距并不明显。这时多进程的稳定性和易于调试的特点就会突显出来。

参考文献

多线程 or 多进程 (转强力推荐)

进程的堆栈空间

线程使用共享堆而非私有堆的原因分析

《Linux程序设计(第四版)》11章,12章


评论