多进程与多线程区别

本文探讨了Unix系统中多线程与多进程在编程、并发性能和资源消耗上的区别。通过实验对比,发现在Linux 2.6内核环境下,多线程并未表现出速度优势,且在高并发时可能出现线程栈问题,而多进程在并发上有其优势。实验结果显示,多线程在创建和销毁效率上比多进程快5~6倍,但在实际应用中,由于并发服务的不可测性,选择多进程或多线程需综合考虑多种因素。
摘要由CSDN通过智能技术生成

在Unix上编程采用多线程还是多进程的争执由来已久,这种争执最常见到在C/S通讯中服务端并发技术 的选型上,比如WEB服务器技术中,Apache是采用多进程的(perfork模式,每客户连接对应一个进程,每进程中只存在唯一一个执行线程), Java的Web容器Tomcat、Websphere等都是多线程的(每客户连接对应一个线程,所有线程都在一个进程中)。

从Unix发展历史看,伴随着Unix的诞生进程就出现了,而线程很晚才被系统支持,例如Linux直到内核2.6,才支持符合Posix规范的NPTL线程库。进程和线程的特点,也就是各自的优缺点如下:

进程优点:编程、调试简单,可靠性较高。
进程缺点:创建、销毁、切换速度慢,内存、资源占用大。
线程优点:创建、销毁、切换速度快,内存、资源占用小。
线程缺点:编程、调试复杂,可靠性较差。

上面的对比可以归结为一句话:“线程快而进程可靠性高”。线程有个别名叫“轻量级进程”,在有的书籍资料上介绍线程可以十倍、百倍的效率快于进程; 而进程之间不共享数据,没有锁问题,结构简单,一个进程崩溃不像线程那样影响全局,因此比较可靠。我相信这个观点可以被大部分人所接受,因为和我们所接受 的知识概念是相符的。

在写这篇文章前,我也属于这“大部分人”,这两年在用C语言编写的几个C/S通讯程序中,因时间紧总是采用多进程并发技术,而且是比较简单的现场为 每客户fork()一个进程,当时总是担心并发量增大时负荷能否承受,盘算着等时间充裕了将它改为多线程形式,或者改为预先创建进程的形式,直到最近在网 上看到了一篇论文《Linux系统下多线程与多进程性能分析》作者“周丽 焦程波 兰巨龙”,才认真思考这个问题,我自己也做了实验,结论和论文作者的相似,但对大部分人可以说是颠覆性的。

下面是得出结论的实验步骤和过程,结论究竟是怎样的? 感兴趣就一起看看吧。

 

实验代码使用周丽论文中的代码样例,我做了少量修改,值得注意的是这样的区别:

论文实验和我的实验时间不同,论文所处的年代linux内核是2.4,我的实验linux内核是2.6,2.6使用的线程库是NPTL,2.4使用的是老的Linux线程库(用进程模拟线程的那个LinuxThread)。

论文实验和我用的机器不同,论文描述了使用的环境:单 cpu 机器基本配置为:celeron 2.0 GZ, 256M, Linux 9.2,内核 2.4.8。我的环境是我的工作本本:单cpu单核celeron(R) M 1.5 GZ,1.5G内存,ubuntu10.04 desktop,内核2.6.32。

进程实验代码(fork.c):

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <signal.h>
  4.  
  5. #define P_NUMBER 255    /* 并发进程数量 */
  6. #define COUNT 100       /* 每进程打印字符串次数 */
  7. #define TEST_LOGFILE "logFile.log"
  8. FILE *logFile =  NULL;
  9.  
  10. char *s =  "hello linux\0";
  11.  
  12. int main ( )
  13. {
  14.      int i =  0,j =  0;
  15.     logFile = fopen (TEST_LOGFILE,  "a+" )/* 打开日志文件 */
  16.      for (i =  0; i < P_NUMBER; i++ )
  17.      {
  18.          if (fork ( ) ==  0 )  /* 创建子进程,if(fork() == 0){}这段代码是子进程运行区间 */
  19.          {
  20.              for (j =  0;j < COUNT; j++ )
  21.              {
  22.                  printf ( "[%d]%s\n", j, s )/* 向控制台输出 */
  23.                 fprintf (logFile, "[%d]%s\n", j, s )/* 向日志文件输出 */
  24.              }
  25.             exit ( 0 )/* 子进程结束 */
  26.          }
  27.      }
  28.  
  29.      for (i =  0; i < P_NUMBER; i++ )  /* 回收子进程 */
  30.      {
  31.         wait ( 0 );
  32.      }
  33.  
  34.      printf ( "OK\n" );
  35.      return  0;
  36. }

进程实验代码(thread.c):

  1. #include <pthread.h>
  2. #include <unistd.h>
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5.  
  6. #define P_NUMBER 255    /* 并发线程数量 */
  7. #define COUNT 100       /* 每线程打印字符串次数 */
  8. #define Test_Log "logFIle.log"
  9. FILE *logFile =  NULL;
  10.  
  11. char *s =  "hello linux\0";
  12.  
  13. print_hello_linux ( )  /* 线程执行的函数 */
  14. {
  15.      int i =  0;
  16.      for (i =  0; i < COUNT; i++ )
  17.      {
  18.          printf ( "[%d]%s\n", i, s )/* 向控制台输出 */
  19.         fprintf (logFile,  "[%d]%s\n", i, s )/* 向日志文件输出 */
  20.      }
  21.     pthread_exit ( 0 )/* 线程结束 */
  22. }
  23.  
  24. int main ( )
  25. {
  26.      int i =  0;
  27.     pthread_t pid [P_NUMBER ]/* 线程数组 */
  28.     logFile = fopen (Test_Log,  "a+" )/* 打开日志文件 */
  29.  
  30.      for (i =  0; i < P_NUMBER; i++ )
  31.         pthread_create (&pid [i ]NULL( void * )print_hello_linux,  NULL )/* 创建线程 */
  32.  
  33.      for (i =  0; i < P_NUMBER; i++ )
  34.         pthread_join (pid [i ], NULL )/* 回收线程 */
  35.  
  36.     
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值