1.多进程与多线程并发速度的实验对比
在多进程与多线程并发运行速度的问题上,一般认为线程的创建销毁速度快,进程的创建销毁速度慢,多线程的速度要优于多进程。
为了得到明确结果,在192.168.1.141的主机上使用了thread.c和fork.c两个程序进行测试。
(测试程序基于论文《Linux系统下多线程与多进程性能分析》作者“周丽焦程波兰巨龙”)
fork.c
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#define P_NUMBER 127
#define COUNT 50
#define P_NUMBER 127 /* 并发进程数量*/
#define COUNT 50 /* 每进程打印字符串次数*/
char *s = "hello linux\0";
int main(void)
{
int i = 0, j = 0;
logFile = fopen(TEST_LOGFILE, "a+");
for (i = 0;i < P_NUMBER; i ++){
if (fork() == 0){
for (j = 0;j < COUNT; j ++){
printf("[%d]%s\n", j, s);
fprintf(logFile, "[%d]%s\n", j, s);
}
exit(0);
}
}
for (i = 0;i < P_NUMBER; i ++){
wait(0);
}
}
thread.c
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#define P_NUMBER 127 /* 并发线程数量*/
#define COUNT 50 /* 每线程打印字符串次数*/
#define Test_Log "logFile.log"
FILE *logFile = NULL;
char *s = "hello linux\0";
print_hello_linux() /* 线程执行的函数*/
{
int i = 0;
for(i = 0; i < COUNT; i ++)
{
printf("[%d]%s\n", i, s); /* 向控制台输出*/
fprintf(logFile, "[%d]%s\n", i, s); /* 向日志文件输出*/
}
pthread_exit(0); /* 线程结束*/
}
int main()
{
int i = 0;
pthread_t pid[P_NUMBER]; /* 线程数组*/
logFile = fopen(Test_Log, "a+"); /* 打开日志文件*/
for (i = 0; i < P_NUMBER; i ++)
pthread_create(&pid[i], NULL, (void *)print_hello_linux, NULL); /* 创建>
线程*/
for (i = 0; i < P_NUMBER; i ++)
pthread_join(pid[i], NULL); /* 回收线程*/
printf("over\n");
return 0;
}
在测试过程中,通过改变P_NUMBER和COUNT两个宏定义值,调整程序的执行。
测试结果如下表所示。
(实验数据均为经过5次运行得到的平均数据)
从实验结果中可以看出,在数据量较小且不进行数据共享时,多进程程序和多线程程序在并发处理上速度并没有明显的差别。
当数据量变大时,多进程有变慢的趋势。
在系统中,会有进程数量和线程数量限制,进程数量可通过“ulimit -a”命令查询,192.168.1.141上的默认进程数限制为1024个。
线程数量主要受虚拟内存和栈内存大小限制,192.168.1.141上默认线程数限制为1019个。
进程最大数量和线程最大数量均可修改。
2.多进程与多线程的性能对比
在不同的性能指标上,多进程与多线程有不同的优缺点,主要对比如下表所示。
3.结论
根据上一节的性能对比,可以得到以下结论。
i.需要频繁的创建与销毁,优先使用线程。
比如说在web应用中,需要频
繁的创建与销毁连接,这时使用多线程为佳。
ii.后台需要大量的计算,优先使用线程。
一般需要保证用户界面响应速度的系统都需要使用多线程,将后台运算和用户界面分成两个线程。
iii.需要保证系统的稳定性,使用进程。
对于需要长时间保持运行的程序,尽量使用进程。
iv.可能扩展到多机分布的优先使用进程,多核分布优先使用线程。
多线程对比多进程,优势在于多核CPU利用率高,在多核分布时优先使用线程。
当需要扩展到其它机器时,使用进程。
v.功能上有很强的相关性,使用线程;功能上相关性不高,使用进程。
比如在服务器上需要完成如下任务:消息收发、消息处理。
“消息收发”和“消息处理”就是弱相关的任务,而“消息处理”里面可能又分为“消息解码”、“业务处理”,这两个任务相对来说相关性就要强多了。
因此“消息收发”和“消息处理”可以分进程设计,“消息解码”、“业务处理”可以分线程设计。