メインコンテンツまでスキップ

Process

Overview

言語ごとで比較される項目のプロセスやスレッドについてまとめているセクション。

マルチスレッドかマルチプロセスかと、並行処理か並列処理かの間に関係性はない。

  • マルチスレッドで並列処理
  • マルチプロセスで並行処理
  • マルチプロセスで並列処理

マルチスレッドを使う場合は並行処理か並列処理かによらずスレッドセーフかどうかを考える必要がある。 並列処理ができるかどうかはCPUのコア数に依存する。コア数が2以上であれば並列処理ができる。

前提

プログラムの並列処理にはマルチスレッドマルチプロセスの2種類がある。

  • マルチスレッド 同じプロセス内で動作し、同じメモリ空間を共有するため、スレッド間でのデータ共有を効率的に行うことができる。
  • マルチプロセス プロセスごとに独立したメモリ空間を持ち、プロセス間通信ができる。

並行処理と並列処理とは

Image from Gyazo

並行処理と並列処理の違いは、タスクの分割・実行において、同時に行われるか否か。

  • 並行処理 複数のタスクを同時に処理することを指し、処理Aと処理Bが交互に実行されるイメージ。
  • 並列処理 複数のタスクを同時に実行することを指し、処理Aと処理Bが同時に実行されるイメージ

プロセスとスレッドの違い

  • プロセス メモリ空間やCPU時間など、システムリソースを割り当てられた実行単位。 プロセスは複数のスレッドで構成されることがある。
  • スレッド プロセス内で実行される、より小さな実行単位。

プロセスは独立した実行環境を持っており、別のプロセスとは独立に動作する。 一方で、スレッドは同じプロセス内で共有されるメモリ空間やファイルハンドル、その他のシステムリソースを共有している。つまり、スレッドはプロセス内での並行処理を行うための単位であり、複数のスレッドが同時に実行されることがあるもの。

マルチスレッドとマルチプロセス

「マルチスレッドとマルチプロセス」と「並行処理と並列処理」は別々で考えないといけないよ

  • マルチスレッドとは 1つのプログラムを複数に分割し、同時に処理を進める技術のこと。 つまり、1つのプログラム内で複数の処理を同時に実行できる。 スレッドは軽量で同じプロセス内であるため、スレッド同士でのデータの共有が容易。 また、プロセスの生成や破棄が必要なく、プログラマの手間も少なくて済む。 ただし、スレッド同士が同じデータにアクセスするときには、注意が必要で、スレッドの中で排他制御を行わなければデータ競合が起こる可能性(スレッドセーフの話)
  • マルチプロセスとは 1つのプログラムを複数に分割し、複数のプロセスで同時に処理を進める技術のこと。 つまり別々のプログラム間(別々の実行環境)でデータをやりとりしながら処理を進めることができる。 プロセスは重量で、まったく別のプロセスとして実行されるため、プロセス間でデータの共有には特殊な手法が必要であり、プロセスの生成や破棄には時間とリソースが必要。

マルチプロセスとマルチスレッドの比較

項目マルチプロセスマルチスレッド
並列処理の単位プロセスごと1つのプロセス内の複数スレッド
メモリ共有共有されない共有される
独立性高い(独立したメモリ空間)低い(メモリ空間を共有)
オーバーヘッド高い(プロセス生成コストが高い)低い(スレッド生成は軽量)
用途PHP、ApacheなどNode.jsのイベントループ、Javaなどの並列処理

マルチプロセスモデル

マルチプロセスモデルとは、リクエストごとに独立したプロセスを立ち上げて処理する方式です。そのため、1つのリクエストが1つのプロセスに対応し、そのプロセスは1つのスレッド(シングルスレッド)で処理される。

各言語の基本モデルと並行処理方法

それぞれの言語は異なる並行処理モデルを採用しており、用途やユースケースに応じた選択が重要。

  1. PHP
    基本モデル
    マルチプロセス
    特徴
    リクエストごとに新しいプロセスを生成する。
    1プロセスは1スレッドで処理。
    メモリ空間はプロセスごとに独立しているため、並列処理は「プロセス」単位。

    ApacheやNginx + PHP-FPMで各リクエストにプロセスを割り当てる。
    利点
    リクエストがプロセス単位なので他のリクエストの影響を受けにくい。
    欠点
    プロセスの生成コストが高く、多数のリクエストに対してメモリ効率が悪い。
  2. JavaScript (ブラウザ)
    基本モデル
    シングルスレッド + イベントループ(非同期処理)
    特徴
    JavaScriptはシングルスレッドで動作。
    ブロッキングしない非同期処理(Promise、async/await、setTimeoutなど)を使って並行処理を実現。
    Web Workersを使用するとマルチスレッド処理が可能。

    fetch() で非同期通信をし、他の処理をブロックせずに待つ。
    利点
    非同期処理を効率的に管理でき、スレッド競合が発生しない。
    欠点
    シングルスレッドなのでCPU負荷の高い処理には不向き。
  3. Node.js
    基本モデル
    シングルスレッド + 非同期イベントループ
    特徴
    基本はJavaScriptと同じくシングルスレッド。
    重い計算を避け、非同期処理を活用してスループットを向上。
    worker_threadsを使えばマルチスレッド処理もできるが、あまり一般的ではない。
    利点
    IO待ちが多い処理(DB操作、HTTPリクエストなど)に強い。
    欠点
    CPU集約型処理には弱い。
  4. Java
    基本モデル
    マルチスレッド
    特徴
    マルチスレッドを標準でサポートしており、1つのプロセス内で複数のスレッドを生成可能。
    スレッドプールやExecutorServiceを使って並行処理を制御。
    スレッド間のデータ共有には同期処理やロックが必要。
    利点
    CPU集約型処理や並列処理に非常に強い。
    欠点
    スレッド間のデータ競合を防ぐため、適切なロックや同期が必要。
  5. Ruby
    基本モデル
    マルチスレッド(ただしGILの制約あり)
    特徴
    Rubyの標準実装(MRI)はグローバルインタプリタロック(GIL)があり、スレッドは1つずつ実行される。
    非同期IOやネットワーク操作では別スレッドが動けるため、並列処理はある程度可能。
    JRuby(JavaベースのRuby実装)ではGILがなく、完全なマルチスレッドが可能。
    利点
    簡単にスレッドを生成でき、Railsなどで非同期処理を追加可能。
    欠点
    標準実装では並列処理のパフォーマンスが制限される。
  6. Ruby on Rails (フレームワーク)
    基本モデル
    マルチプロセス + マルチスレッド
    特徴
    アプリケーションサーバー(Pumaなど)によってプロセスを複数立ち上げ、各プロセス内でマルチスレッドで処理。
    デフォルト設定では、スレッドセーフなコードを要求。
    利点
    複数のリクエストを効率的に処理可能。
    欠点
    マルチスレッドでスレッドセーフでないコードがあると競合が発生する。
  7. Flutter (Dart)
    基本モデル
    マルチスレッド(Isolate)
    特徴
    Dartではスレッドの代わりにIsolateと呼ばれる並行処理単位を使う。
    各Isolateは独自のメモリ空間を持つため、スレッド間での競合がない。
    Isolate同士はメッセージを使って通信。
    利点
    スレッド間競合がなく、並行処理がシンプル。
    欠点
    Isolate間通信のメッセージパッシングにオーバーヘッドがある。

言語の並行処理モデル表

ポイント PHPは1プロセス1スレッドで処理されるため、プロセスごとにメモリが分離されており、並列処理はスレッドではなくプロセス単位。
Node.jsやJavaScriptは非同期処理を使ってシングルスレッド内で効率的に並行処理を行う。
JavaやFlutterのように、マルチスレッドを活用した本格的な並行処理が可能な言語もある。 Rubyの標準実装はGILの影響で同時に動けるスレッド数が制限されますが、非同期IOでは他スレッドを実行可能。

言語/フレームワーク並行処理モデル詳細
PHPマルチプロセスリクエストごとにプロセスを生成。各プロセスは1つのスレッドのみで処理する。
JavaScript (ブラウザ)シングルスレッド + 非同期イベントループJavaScriptのランタイムはイベントループを用いて非同期処理を並行処理するが、スレッドは1つのみ。Web Workersを使用すればマルチスレッド処理が可能。
Node.jsシングルスレッド + 非同期イベントループ + Worker Threads(マルチスレッド対応可)Node.jsは非同期処理で並行処理を実現するが、デフォルトではシングルスレッド。worker_threadsを使えばマルチスレッド処理が可能。
JavaマルチスレッドJavaはデフォルトでマルチスレッド対応。スレッドプールや並列処理用のライブラリが充実している。
RubyマルチスレッドRubyはマルチスレッド対応だが、MRI(標準実装)は**グローバルインタプリタロック(GIL)**により、1つのスレッドしか同時実行されない。ただし、IO待ちなど非CPU処理の際には別スレッドが動く。
Ruby on Railsマルチプロセス + マルチスレッドPumaなどのアプリケーションサーバーで並列処理を行う。マルチスレッド対応もしているが、スレッドセーフなコードが必要。
Flutter (Dart)マルチスレッドDartはIsolateと呼ばれる軽量なスレッドを使用して並行処理を行う。各Isolateはメモリ空間を共有せず、メッセージで通信する。