这是我关于stackoverflow的第一篇文章,我的母语不是英语。请原谅我给您带来的不便。也许有点长,所以我期待您的耐心。提前致谢!

我有一个C语言代码段。这项工作是计算两个文件中的单词数。我使用pthreads解决了这个问题。但是我发现这两个语句的顺序



影响程序的性能,这与我的预期相反。这是代码:

#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;
}

性能:

我在命令行上使用“test program_name”运行程序以测试运行速度。输出为:

如果命令是这样的:



程序运行速度快:真正的0.014s

如果这样:



程序运行缓慢:实际为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次。定义COUNT20。以下是更改后的代码:
#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;
}

fast_version(首先是count_word())和slow_version(首先是pthread_create())的输出:

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
// ...
}

添加语句“printf(” from%s\n“,filename);”,这样我就可以知道当时正在运行哪个文件(或线程)。快速版本的输出是“from file1”的20倍,然后是“file2”的20倍,而慢速版本的输出是“from file1”和“from file2”混合打印。

快速版本看起来更快,因为没有上下文切换。但是事实是,在count_word()完成之后,原始线程并没有死,而是创建了一个新线程并等待其终止。新线程运行时是否没有上下文切换?我仔细观察了屏幕,发现“from file2”的打印速度显然比“from file1”的打印速度慢。为什么?是因为从file2计数时发生了上下文切换吗?

对于慢速版本,从输出中我们可以看到“from file1”和“from file2”的打印速度甚至比快速版本中“from file2”的打印速度还要慢,因为它的上下文切换在并行计数上花费了更多时间。 ,而在快速版本中,上下文切换并不那么繁琐,因为其中一个线程已完成其工作并仅在等待。

因此,我认为主要原因是快速版本相对于慢速版本具有轻松的上下文切换。但是“打印速度”是根据我的观察得出的,可能并不那么严格。所以我不确定。

最佳答案

在评论中,您写道:



由于只有一个核心,因此无论如何线程执行都将被序列化。当两个线程同时运行时,由于每个线程都执行阻塞的I/O,因此要付出线程上下文切换的开销。

当第一个线程完成执行后启动第二个线程时,没有上下文切换开销。

10-06 05:49
查看更多