Yan*_*hao 7 c unix performance multithreading pthreads
这是我在stackoverflow上的第一篇文章,我的母语不是英语.对于这篇文章带给您的任何不便,请原谅.也许它有点长,所以我很期待你的耐心.提前致谢!
我有一个C语言代码段.这项工作是计算两个文件中的单词数.我使用pthreads来解决这个问题.但我找到了这两个陈述的顺序
count_words(的argv [1]);
pthread_create(&t1,NULL,count_words,(void*)argv [2]);
影响程序性能,这与我的预期相反.这是代码:
#include <stdio.h>
#include <pthread.h>
#include <ctype.h>
#include <stdlib.h>
int total_words;
int main(int argc, char *argv[]) {
pthread_t t1;
void *count_words(void *);
if (argc != 3) {
printf("usage: %s file1 file2\n", argv[0]);
exit(1);
}
total_words = 0;
count_words(argv[1]); // program runs faster when executing this first
pthread_create(&t1, NULL, count_words, (void *)argv[2]);
pthread_join(t1, NULL);
printf("%5d: total words\n", total_words);
return 0;
}
void *count_words(void *f) {
char *filename = (char *)f;
FILE *fp;
int c, prevc = '\0';
if ((fp = fopen(filename, "r")) == NULL) {
perror(filename);
exit(1);
}
while ((c = getc(fp)) != EOF) {
if (!isalnum(c) && isalnum(prevc))
total_words++;
prevc = c;
}
fclose(fp);
return NULL;
}
Run Code Online (Sandbox Code Playgroud)
性能:
我在命令行上使用"test program_name"运行程序来测试运行速度.输出是:
如果顺序如下:
count_words(的argv [1]);
pthread_create(&t1,NULL,count_words,(void*)argv [2]);
程序运行速度快:真正的0.014s
如果像这样:
pthread_create(&t1,NULL,count_words,(void*)argv [2]);
count_words(的argv [1]);
程序运行缓慢:真正的0.026s
我的期望:
在案例1中,程序首先运行count_word().完成计数作业后,它将继续运行pthread_create().那时,新线程将有助于完成计数工作.因此,新线程在原始线程完成作业后执行作业,该作业是顺序运行而不是并行运行.在案例2中,程序在任何计数之前首先运行pthread_create(),因此在此之后有两个并行的线程进行计数.所以我希望案例2比案例1快.但我错了.案例2较慢.有人能给我一些有用的信息吗?
注意
请忽略我没有在全局变量total_words上放置互斥锁.这不是我关心的部分.该计划仅用于测试.请原谅其不完美之处.
编辑1
以下是我阅读一些建议后的补充和改进.
a)补充:处理器是Intel®Celeron(R)CPU 420 @ 1.60GHz.一个核心.
b)改进:我改进了我的例子,改变了两个:
1)我放大了文件.file1是2080651字节(大约2M),file2是file1的副本.
2)我修改了count_words().到达文件末尾时,使用fseek()将fp设置为开头并再次计数.反复计算COUNT次.定义COUNT 20.以下是更改的代码:
#define COUNT 20
// other unchanged codes ...
void *count_words(void *f) {
// other unchanged codes ...
int i;
for (i = 0; i < COUNT; i++) {
while ((c = getc(fp)) != EOF) {
if (!isalnum(c) && isalnum(prevc))
total_words++;
prevc = c;
}
fseek(fp, 0, SEEK_SET);
}
fclose(fp);
return NULL;
}
Run Code Online (Sandbox Code Playgroud)
输出fast_version(count_word()first)和slow_version(pthread_create()first):
administrator @ ubuntu:〜$ time ./fast_version file1 file2
12241560:总字数
真正的0m5.057s
用户0m4.960s
sys 0m0.048s
administrator @ ubuntu:〜$ time ./slow_version file1 file2
12241560:总字数
真正的0m7.636s
用户0m7.280s
sys 0m0.048s
我试了几次"time progname file1 file2"命令.也许每次跑步都有十分之一秒或百分之一秒的差异.但差异并不大.
编辑2
根据一些提示,在我做了一些实验之后添加了这部分 -
在第一个线程完成它的执行后启动第二个线程时,没有上下文切换开销.
--by user315052.
实验是我改进了count_word():
void *count_word(void *f) {
// unchanged codes
// ...
for (i = 0; i < COUNT; i++) {
while ((c = getc(fp)) != EOF) {
if (!isalnum(c) && isalnum(prevc))
total_words++;
prevc = c;
}
fseek(fp, 0, SEEK_SET);
printf("from %s\n", filename); // This statement is newly added.
}
// unchanged codes
// ...
}
Run Code Online (Sandbox Code Playgroud)
添加语句"printf("来自%s \n",文件名);",所以我可以告诉当时正在运行的文件(或线程).快速版本的输出是"从文件1"的20倍,然后是"从文件2"的20倍,慢速版本是"从文件1"和"从文件2"混合打印.
看起来快速版本更快,因为没有上下文切换.但事实是,在count_word()完成后,原始线程没有死,但创建了一个新线程并等待它终止.新线程运行时是否没有上下文切换?我仔细观察了屏幕,发现"from file2"的打印速度明显慢于"from file1".为什么?是因为从file2计数时发生了上下文切换吗?
对于慢速版本,我们可以从输出中看到"from file1"和"from file2"的打印速度甚至比快速版本中"from file2"的打印速度慢,因为它的上下文切换在并行计数上花费的时间更多在快速版本中,上下文切换并不像其中一个线程完成其工作而只是等待那么重.
所以我认为主要原因是快速版本具有轻松简单的上下文切换速度.但"印刷速度"来自我的观察,可能不是那么严格.所以我不确定.
jxh*_*jxh 10
在评论中,你写道:
该处理器是Intel®Celeron(R)CPU 420 @ 1.60GHz.一个核心.
由于您只有一个核心,因此无论如何都会对您的线程执行进行序列化.同时运行两个线程的程序会支付线程上下文切换的开销,因为每个线程执行阻塞I/O.
在第一个线程完成它的执行后启动第二个线程时,没有上下文切换开销.