为什么n个线程的平均速度不如C中的单个线程快?

为什么n个线程的平均速度不如C中的单个线程快?,c,multithreading,C,Multithreading,我写了一个程序,有两个线程做同样的事情,但是我发现每个线程的吞吐量都比我只产生一个线程慢。然后我编写这个简单的测试,看看这是我的问题还是因为系统的原因 #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <time.h> /* * Function: run_add * ----------------------- * Do addition oper

我写了一个程序,有两个线程做同样的事情,但是我发现每个线程的吞吐量都比我只产生一个线程慢。然后我编写这个简单的测试,看看这是我的问题还是因为系统的原因

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <time.h>


/*
 * Function: run_add
 * -----------------------
 * Do addition operation for iteration ^ 3 times
 *
 * returns: void
 */
void *run_add(void *ptr) {
  clock_t t1, t2;
  t1 = clock();

  int sum = 0;
  int i = 0, j = 0, k = 0;
  int iteration = 1000;
  long total = iteration * iteration * iteration;
  for (i = 0; i < iteration; i++) {
    for (j = 0; j < iteration; j++) {
      for (k = 0; k < iteration; k++) {
        sum++;
      }
    }
  }

  t2 = clock();
  float diff = ((float)(t2 - t1) / 1000000.0F );
  printf("thread id = %d\n", (int)(pthread_self()));
  printf("Total addtions: %ld\n", total);
  printf("Total time: %f second\n", diff);
  printf("Addition per second: %f\n", total / diff);
  printf("\n");

  return NULL;
}


void run_test(int num_thread) {
  pthread_t pth_arr[num_thread];
  int i = 0;
  for (i = 0; i < num_thread; i++) {
    pthread_create(&pth_arr[i], NULL, run_add, NULL);
  }

  for (i = 0; i < num_thread; i++) {
    pthread_join(pth_arr[i], NULL);
  }
}

int main() {
  int num_thread = 5;
  int i = 0;
  for (i = 1; i < num_thread; i++) {
    printf("Running SUM with %d threads. \n\n", i);
    run_test(i);
  }
  return 0;
}
结果仍然显示,n个线程的平均速度比单个线程慢。我拥有的线程越多,每个线程的速度就越慢

结果如下:

使用1个线程运行SUM

螺纹id=528384, 加总:100000000, 总时间:1.441257秒, 每秒添加数:6938784.000000

使用2个线程运行SUM

螺纹id=528384, 加总:100000000, 总时间:2.970870秒, 每秒添加数:336601728.000000

线程id=1064960, 加总:100000000, 总时间:2.972992秒, 每秒添加数:336361504.000000

使用3个线程运行SUM

线程id=1064960, 加总:100000000, 总时间:4.434701秒, 每秒添加数:225494352.000000

螺纹id=1601536, 加总:100000000, 总时间:4.449250秒, 每秒添加数:224756976.000000

螺纹id=528384, 加总:100000000, 总时间:4.454826秒, 每秒添加数:224475664.000000

使用4个线程运行SUM

螺纹id=528384, 加总:100000000, 总时间:6.261967秒, 每秒添加数:159694224.000000

线程id=1064960, 加总:100000000, 总时间:6.293107秒, 每秒添加数:15890416.000000

螺纹id=2138112, 加总:100000000, 总时间:6.295047秒, 每秒添加数:15885056.000000

螺纹id=1601536, 加总:100000000, 总时间:6.306261秒, 每秒添加数:158572560.000000

我有一个4核CPU,我的系统监视器显示每次我运行n个线程时,n个CPU核的利用率为100%。n线程时钟测量的是CPU时间而不是墙时间,这是真的吗。 它还测量所有线程的总时间

CPU时间是处理器执行代码的时间,墙上的时间是真实世界中经过的时间,就像墙上的时钟显示的那样

使用/usr/bin/time对程序计时,以查看实际发生的情况。 或者使用墙时间函数,如time、gettimeofday或clock\u gettime


clock_gettime可以测量此线程、此进程的CPU时间或挂机时间。-这可能是做这类实验的最佳方法。

虽然您对多线程性能为何看起来比单线程差有自己的答案,但您可以做一些事情来清理程序的逻辑,并使其按照预期的方式工作

首先,如果您跟踪经过的相对墙壁时间和时钟时间差报告的时间,您会注意到报告的时间大约是实际墙壁时间的n处理器内核倍数。另一个答案解释了这一点

对于相对的单核性能定时,可以使用时钟。您只获得了墙时间的近似值,但要查看每秒的相对添加量,就可以清楚地看到每个核心的性能

虽然您已经正确地为diff使用了1000000除数,但time.h为您提供了一个方便的定义。POSIX要求每秒时钟数等于1000000,与实际分辨率无关。该常数以时间为单位提供

接下来,您还应该注意到,直到所有线程都被连接起来,每个核心的输出才被报告,这使得在run_add中报告总数有些毫无意义。为了方便起见,您可以从各个线程输出thread_id等,但是在所有线程加入后,应该在调用函数中重新计算计时信息。这将大大理清你跑步的逻辑。此外,如果希望能够改变迭代次数,则应该考虑通过PTR传递该值。e、 g:

将所有的部分放在一起,您可以编写一个工作示例,如下所示。确保禁用优化以防止编译器优化sum等循环

大约每秒增加4.65亿个。使用两个磁芯应使该速率加倍:

$ ./bin/pthread_one_per_core 2

running sum with 2 threads.

  thread id  = 140437156796160
  iterations = 1000000000

  thread id  = 140437165188864
  iterations = 1000000000

----------------
Total time: 2.152436 second
Total addtions: 2000000000
Additions per-second: 929179560.000957
在929M/s的速度下,每秒的添加量正好是原来的两倍。使用4芯:

$ ./bin/pthread_one_per_core 4

running sum with 4 threads.

  thread id  = 139867841853184
  iterations = 1000000000

  thread id  = 139867858638592
  iterations = 1000000000

  thread id  = 139867867031296
  iterations = 1000000000

  thread id  = 139867850245888
  iterations = 1000000000

----------------
Total time: 2.202021 second
Total addtions: 4000000000
Additions per-second: 1816513309.422720
再次加倍至1.81G/s,使用8芯可获得预期结果:

$ ./bin/pthread_one_per_core

running sum with 8 threads.

  thread id  = 140617712838400
  iterations = 1000000000

  thread id  = 140617654089472
  iterations = 1000000000

  thread id  = 140617687660288
  iterations = 1000000000

  thread id  = 140617704445696
  iterations = 1000000000

  thread id  = 140617662482176
  iterations = 1000000000

  thread id  = 140617696052992
  iterations = 1000000000

  thread id  = 140617670874880
  iterations = 1000000000

  thread id  = 140617679267584
  iterations = 1000000000

----------------
Total time: 2.250243 second
Total addtions: 8000000000
Additions per-second: 3555171004.558562
3.55G/s。请查看当前的两个答案,如果您有任何问题,请告诉我们


注意:有许多额外的清理和验证可以应用,但就您的示例而言,将类型更新为rational unsigned可以防止使用线程id和加法编号产生奇怪的结果。

我很惊讶程序没有立即运行;您是在启用优化的情况下编译的吗?@Hurkyl我编译它时使用:gcc xxx.c-lpthread您的多线程处理错误了。所有的线程都在运行
完全相同的工作,他们都做所有的工作。这不能加快进程。您必须在所有线程之间分配工作。@Luke:如果没有优化,性能测试将毫无意义。添加-O2或-O3之后,您可能需要发布一个关于如何编写不会被优化的繁忙工作循环的新问题。另外,我认为gcc也喜欢用线程编译另一个标志-线程或-thread或-pthread或类似的东西?时钟测量CPU时间,而不是墙时间+1。也许您应该对此进行丰富,使其成为更好的答案。我很确定很多用户不知道这意味着什么。
$ ./bin/pthread_one_per_core 1

running sum with 1 threads.

  thread id  = 140380000397056
  iterations = 1000000000

----------------
Total time: 2.149662 second
Total addtions: 1000000000
Additions per-second: 465189411.172547
$ ./bin/pthread_one_per_core 2

running sum with 2 threads.

  thread id  = 140437156796160
  iterations = 1000000000

  thread id  = 140437165188864
  iterations = 1000000000

----------------
Total time: 2.152436 second
Total addtions: 2000000000
Additions per-second: 929179560.000957
$ ./bin/pthread_one_per_core 4

running sum with 4 threads.

  thread id  = 139867841853184
  iterations = 1000000000

  thread id  = 139867858638592
  iterations = 1000000000

  thread id  = 139867867031296
  iterations = 1000000000

  thread id  = 139867850245888
  iterations = 1000000000

----------------
Total time: 2.202021 second
Total addtions: 4000000000
Additions per-second: 1816513309.422720
$ ./bin/pthread_one_per_core

running sum with 8 threads.

  thread id  = 140617712838400
  iterations = 1000000000

  thread id  = 140617654089472
  iterations = 1000000000

  thread id  = 140617687660288
  iterations = 1000000000

  thread id  = 140617704445696
  iterations = 1000000000

  thread id  = 140617662482176
  iterations = 1000000000

  thread id  = 140617696052992
  iterations = 1000000000

  thread id  = 140617670874880
  iterations = 1000000000

  thread id  = 140617679267584
  iterations = 1000000000

----------------
Total time: 2.250243 second
Total addtions: 8000000000
Additions per-second: 3555171004.558562