为什么所有线程总是占用相同的时间,为什么OS 运行 所有线程都"in parallel"?

Why do all threads always take the same time, why does the OS run all threads "in parallel"?

为什么每个线程的时间量总是相等,所有线程都执行相同的指令?

我已经设置了一个程序来测量线程执行特定操作所花费的时间(有关更多详细信息,请参见下文)。我的 MacBook 有 4 个物理内核或 8 个逻辑内核(可用超线程),所以我假设我可以 运行 最多并行 8 个线程。

我希望 OS 到 运行 最多并行 8 个线程,一旦完成,运行 其余线程。但是,与这些预期相反,所有线程(无论多少)似乎总是花费相同的时间。为什么 OS 将它们分开,为什么它启动所有线程而不是先完成前 8 个线程?为什么它尝试 运行 所有这些“并行”(我知道它实际上不能 运行 并行超过 8 个)?

另请参阅下面的 table;每个条代表 n 个线程的 平均 时间,n 从 1 到 17。令人惊讶的是,平均时间等于每个线程的时间(这就是我发现的 odd/don 不明白 - 为什么它们都花费相同的时间?):

这是我使用的一段代码:

#include <stdio.h>
#include <sys/time.h>
#include <pthread.h>

#define MAX 1000000000

void * calculate (void * val) {
  /* only time measurement ... */
  long a = 0, start, end;
  struct timeval timecheck;

  gettimeofday(&timecheck, NULL);
  start = (long)timecheck.tv_sec * 1000 + (long)timecheck.tv_usec / 1000;

  /* actual calculation (just for testing) */
  for (unsigned i = 1; i <= MAX; ++i)
    a += i;

  gettimeofday(&timecheck, NULL);
  end = (long)timecheck.tv_sec * 1000 + (long)timecheck.tv_usec / 1000;

  printf("%ld; time: %ldms\n", a, (end - start));

  return NULL;
}


void main (int argc, char ** argv) {
  pthread_t thread_1, thread_2, thread_3, thread_4; /* thread_5, ...*/
  long a = 0, start, end;
  struct timeval timecheck;

  gettimeofday(&timecheck, NULL);
  start = (long)timecheck.tv_sec * 1000 + (long)timecheck.tv_usec / 1000;

  if (pthread_create(&thread_1, NULL, &calculate, NULL) != 0)
    perror("Couldn't create thread 1");
  /* ... repeat the above two lines for each thread ... */

  pthread_join(thread_1, NULL);
  /* ... repeat the line above for each thread ... */

  gettimeofday(&timecheck, NULL);
  end = (long)timecheck.tv_sec * 1000 + (long)timecheck.tv_usec / 1000;

  printf("total time: %ldms\n", (end - start));
}

why does it start all of the threads instead of finishing say the first 8 threads first?

您要求它创建并启动 17 个线程。所以它创建并启动了 17 个线程。

它无法知道在安排其他任务之前完成 运行 8 是否安全。它甚至不知道这将是有益的。 (想象一下,如果线程大部分时间都处于阻塞状态。)但最重要的是,它甚至不知道线程是否会完成!

也许您想使用线程池模型,在该模型中,您从共享队列中获取的线程数量有限。

Example of a thread pool (in C)

线程池示例(在 Perl 中):

use threads;

use Thread::Queue qw( );

use constant NUM_WORKERS => 10;

sub work {
   my $job = shift;
   ...
}

my $q = Thread::Queue->new();  # A thread-safe queue.

# Create worker threads.
my @threads;
for (1..NUM_WORKERS) {
   push @threads, async {
      while ( defined( my $job = $q->dequeue() ) ) {
         work($job);
      }
   };
}

# Feed them work
for my $job (...) {
    $q->enqueue($job);
}

# $q->dequeue normally blocks when the queue is empty.
# This causes it to return an undef value instead.
$q->end();  

# Wait for the workers to complete the work.
$_->join() for @threads;

有适用于 C 的线程池库。(就此而言,也适用于 Perl。)