プロセスとスレッドの差

問題

プロセスの生成とスレッドの生成ではスレッド生成の方が処理が軽い。プロセスは親プロセスとは別のメモリ空間で動作し、スレッドは同じメモリ空間で動作するので軽いのだ。というのはわかっているんだけど、実際どれくらい速度が違うのかは把握していなかった。

調査

以下の二つのプログラムを実行して、プロセスの場合と、スレッドの場合の実行時間を計測する。計測は time コマンドを使用する。
実行環境

プロセス版

int main(int argc, char *argv[])
{
  int   i;
  int   status;
  int   loop;
  pid_t cpid;
  pid_t w;

  loop = atoi(argv[1]);
  for (i = 0; i < loop; i++) {
    cpid = fork();
    if (cpid == -1) {
      perror("fork");
      exit(EXIT_FAILURE);
    } else if (cpid == 0) {
      _exit(0);
    } else {
      w = waitpid(cpid, &status, 0);
      if (w == -1) {
        perror("waitpid");
        exit(EXIT_FAILURE);
      }
    }
  }
  return 0;
}

スレッド版

void *thread_func(void *argv)
{
  pthread_exit(NULL);
}

int main(int argc, char *argv[])
{
  int i;
  int res;
  int loop;
  pthread_t thread;

  loop = atoi(argv[1]);
  for (i = 0; i < loop; i++) {
    res = pthread_create(&thread, NULL, thread_func, (void *)NULL);
    if (res != 0) {
      perror("pthread_create");
      exit(EXIT_FAILURE);
    }
    pthread_join(thread , NULL);
  }
  return 0;
}
結果

プロセス

% time ./fork 10000
./fork 10000  0.87s user 11.50s system 97% cpu 12.627 total

スレッド

% time ./pthread 10000
./pthread 10000  0.01s user 0.60s system 63% cpu 0.948 total

プロセス/スレッドの生成を10,000回繰り返した。性能差は歴然としている。スレッドの方が13倍程速い。
何が違うのかをシステムコールの面から調べてみる。

  • プロセス
% strace -T ./fork 1

... 略 ...

clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb771c728) = 31601 <0.001170>

... 略 ...
  • スレッド
% strace -T ./pthread 1

... 略 ...

clone(child_stack=0xb77ad494, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0xb77adbd8, {entry_number:6, base_addr:0xb77adb70, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}, child_tidptr=0xb77adbd8) = 31604 <0.000207>

... 略 ...

出力が多かったので、気になった部分以外は省略。気になったのは、clone() を呼んでいる箇所。プロセスだと約0.0012秒に対し、スレッドは約0.0002秒だ。cloneの第2引数にスレッドの場合は CLONE_VM を設定しているが、プロセスの方にはない。CLONE_VM を設定すると、呼び出し元のプロセスと子プロセスは同じメモリ空間で実行される。ということなので、この辺が大きく差が出る要因の一つかな。これだけでは13倍までの差はつかないので、他にも要因はあるだろうけど今日はこれまで。ちなみに、呼んでいるシステムコールの数は予想に反してスレッドの方が多かった。