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

Concurrency

Overview

オペレーティングシステム(OS)における並行処理をまとめたセクション。

並行処理(Concurrency)とは

オペレーティングシステム(OS)における並行処理とは、複数のタスクやプロセスを同時に処理できる能力を指し、これによって効率性や応答性が向上させる。
この並行処理は、マルチスレッドやマルチプロセスを用いて、複数のプロセスやスレッドを同時に、あるいは交互に実行することで実現される。

これにより、複数のプログラムがCPUやメモリなどの共有リソース上で同時に動作できるようになり、以下のような効果がある。

  • システムのパフォーマンス最適化
  • アイドル時間の削減
  • アプリケーションの応答速度向上

オペレーティングシステムにおける並行処理は、リソースの有効活用と応答速度の向上のために不可欠。
プロセスやスレッドを効率よく管理することで、システム全体のパフォーマンスを向上させ、ユーザーエクスペリエンスを改善する。
並行処理の適切な実装には、競合回避やデッドロック防止など、さまざまな課題に対処することが求められる。

並行処理が重要な理由

OSでは、以下のような状況に対応するため、優れた並行処理能力が必要。

  • デッドロック(複数のプロセスが互いに資源を待ち続けて停止する状況)
  • 競合状態(複数のプロセスが同時に同じリソースにアクセスし、予期せぬ動作が起こる状態)
  • 途切れないタスク実行(特定のタスクが中断されないように制御する)

これらの課題に対処するためには、プロセスの実行管理、メモリ割り当て、**スケジューリング(実行順序の調整)**などの技術が不可欠になる。

並行処理の役割

オペレーティングシステムにおける並行処理の目的は、以下の通り。

  1. 物理リソースの共有 マルチユーザー環境では、ハードウェアリソース(CPU、メモリ、ストレージなど)は限られているため、並行処理により効率的に共有します。
  2. 論理リソースの共有 例えば、複数のプロセスが同じファイルを共有し、同じ情報にアクセスする必要がある場合です。
  3. 計算速度の向上 並列実行により、タスク全体の処理速度を向上させます。
  4. モジュール化 システム機能を分割し、個別のプロセスとして処理することで、管理しやすくします。

マルチユーザー環境とは

マルチユーザー環境とは、オペレーティングシステム(OS)が複数のユーザーからの操作を同時に処理できるように設計されたシステムのこと。
この環境は、OSのプロセススケジューリングやメモリ管理などの仕組みによって成り立っている。
各ユーザーはログインすることで、自身のリソース(ファイル、プロセス、セッションなど)を独立して利用できるようになっており、他のユーザーと安全かつ効率的にシステムを共有できる仕組みが整っている。

  • LinuxやUNIX系OS
    • SSHなどで複数のユーザーが同時にログインし、それぞれ異なるターミナルセッションで作業可能とする。
  • サーバーシステム
    • 1つのWebサーバーが複数のユーザーリクエストを処理し、同時に複数のクライアントに応答する。
  • リモートデスクトップ
    • Windowsのリモートデスクトップサービスなど、同時に複数のユーザーがリモート接続してシステムにアクセスできる。
備考

マルチユーザー環境とは、単に「/home/user」のようなディレクトリ構造を指すものではなく、複数のユーザーが同時に1つのシステムを利用できる環境を意味する。 一方、/home/user は、OSがユーザーごとに用意する個別のファイル保存領域であり、ユーザーごとに独立した作業スペースを提供するためのディレクトリ。
これはマルチユーザー環境の一部として機能し、各ユーザーが自身のデータを安全かつ効率的に管理できるよう設計されている。

プロセス間の関係性

OS内で動作するプロセスの種類は、以下の2種類に分けられる。

  1. 独立プロセス(Independent Process) 他のプロセスと直接的なデータ共有をしないプロセス。
    独立して動作し、他のプロセスの状態に影響を受けない。
  2. 協調プロセス(Cooperating Process) 他のプロセスと情報をやり取りし、協力して処理を進めるプロセス。
    これにより、複数のプロセスが同じ目標を達成するために連携します。

並行処理が活用される主な場面 • マルチタスク環境:複数のアプリケーションを同時に実行するためのバックグラウンド処理。 • リアルタイム処理:ユーザーの入力に即座に反応する必要がある場面(ゲーム、IoT、金融システムなど)。 • 高性能コンピューティング:複数のプロセッサを用いて計算を高速化するための並列処理。

スレッドセーフ

スレッドセーフとは マルチスレッドはこんなときに使う

シングルプロセスとシングルスレッド

サーバーを構築するNode.js シングルスレッド&シングルプロセス

シングルスレッドとマルチスレッドの違い

  • シングルスレッド シングルスレッドのプログラムでは、すべてのコードはひとつのスレッドで順次実行されます。 変数はひとつのスレッド内でのみアクセスされるため、データの競合は発生しません。

  • マルチスレッド マルチスレッドのプログラムでは、複数のスレッドが同時に実行され、同じメモリ空間を共有します。 共有される変数は複数のスレッドからアクセスされるため、データの競合が発生する可能性があります。 競合を防ぐためには、適切な同期機構(ミューテックス、セマフォなど)を用いて変数へのアクセスを制御する必要があります。

  1. シングルスレッドモデル:

    • プロセスごとに1リクエスト: シングルスレッドのWebサーバー(例:WEBrick)は、各リクエストを個別のプロセスで処理します。そのため、1つのプロセスは1回に1つのリクエストしか処理しません。
    • 安全性: このモデルでは、各プロセスが独立して動作するため、スレッドセーフなコードを書く必要がなく、リソースの共有による問題を避けることができます。
  2. マルチスレッドモデル:

    • スレッドごとに1リクエスト: マルチスレッドのWebサーバー(例:Puma)は、複数のスレッドを使用して同時に複数のリクエストを処理します。1つのプロセス内で複数のスレッドが動作し、各スレッドが個別のリクエストを処理します。
    • 効率性: これにより、同時に多くのリクエストを効率的に処理できるため、応答性が向上します。

Railsの動作

  • デフォルト設定: Railsアプリケーションはデフォルトでシングルスレッドモードで動作します。ただし、Pumaなどのマルチスレッドサーバーを使用することで、Railsをマルチスレッドモードで動作させることができます。
  • マルチスレッド対応: Railsはマルチスレッド対応しており、適切な設定を行えば、マルチスレッド環境でも安全に動作します。ただし、スレッドセーフなコードを書くことが重要です。

実際の動作例

以下は、Pumaを使用してRailsアプリケーションをマルチスレッドで動作させる設定の例です。この設定により、Railsアプリケーションは同時に複数のリクエストを処理できるようになります。

# config/puma.rb

workers ENV.fetch("WEB_CONCURRENCY") { 2 }
threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
threads threads_count, threads_count

preload_app!

rackup DefaultRackup
port ENV.fetch("PORT") { 3000 }
environment ENV.fetch("RAILS_ENV") { "development" }

on_worker_boot do
ActiveRecord::Base.establish_connection if defined?(ActiveRecord)
end

この設定では、Pumaが2つのワーカーと5つのスレッドで動作するため、同時に最大10のリクエストを処理できます。

結論

  • シングルスレッドモード: 各リクエストは独立したプロセスで処理される。
  • マルチスレッドモード: 複数のスレッドが並行してリクエストを処理する。
  • Railsのサポート: Railsはデフォルトでシングルスレッドですが、Pumaなどを使用することでマルチスレッドで動作させることができる。

これにより、Railsアプリケーションは必要に応じて効率的にスケールさせることが可能です。

シングルスレッドの意味についてもう少し詳しく説明します。

シングルスレッドとは

  • シングルスレッド: 1つのスレッドで実行されるプロセスを指します。これは、1つのタスクが順番に実行されることを意味し、並行処理は行われません。

シングルスレッドの特徴

  • 順次実行: プロセス内の命令が1つのスレッドで順番に実行されます。他の処理が終わるまで次の処理は開始されません。
  • コンテキストスイッチがない: スレッドが1つしかないため、コンテキストスイッチ(実行中のスレッドを別のスレッドに切り替える操作)が発生しません。これにより、オーバーヘッドが減少します。

Node.jsにおけるシングルスレッド

  • イベントループ: Node.jsはシングルスレッドですが、非同期処理を効率的に管理するためのイベントループを利用しています。イベントループは、I/O操作(ファイル読み書き、ネットワーク通信など)を非同期に処理し、CPUのリソースを有効に活用します。
  • 非同期処理: Node.jsは非同期I/O操作をサポートし、コールバックやPromiseを使って、長時間実行されるI/O操作が完了したときに通知を受け取ります。この仕組みにより、他の処理がブロックされることなく並行して実行されます。

シングルスレッドと並行処理

  • 並行処理の限界: シングルスレッドではCPUバウンドなタスク(CPUリソースを多く消費するタスク)を長時間実行すると、他のタスクの実行が遅れます。Node.jsでは、このようなタスクを別のスレッドやプロセスにオフロードするための機能(Worker ThreadsやClusterモジュール)が提供されています。

Lambdaとシングルスレッド

  • Lambda関数の実行環境: AWS Lambda関数は、リクエストごとに独立した実行環境(コンテナ)で実行されます。これにより、1つのリクエストが重い処理を行っても、他のリクエストには影響を与えません。ただし、各Lambda関数はシングルスレッドで動作するため、関数内でCPUバウンドなタスクを実行すると、そのタスクが完了するまで他の処理はブロックされます。

まとめ

シングルスレッドは1つのスレッドで順次実行されるプロセスを指し、Node.jsではイベントループを使って非同期処理を効率的に管理します。AWS Lambdaのような環境では、シングルスレッドの制約がありつつも、独立した実行環境で並行処理を実現しています。シングルスレッド環境では、CPUバウンドなタスクの処理に注意が必要です。

Resource

オペレーティング システムにおける並行性 オペレーティングシステム