Rubyの並列化で激オソご注意!!
ローカル環境で高速だった処理が本番環境で激オソになる目にあいましたので共有です。
結論
Rubyで処理速度を向上させるために、Parallel gemの Parallel.map を使ってスレッド並列化を試みたものの、ローカル環境では問題なかったのに本番環境で劇的に遅くなってしまった経験はありませんか?
実は、Parallel.map はデフォルトでプロセス並列化を行うため、アクセス数の多い本番環境ではプロセスの立ち上げコストが大きな負荷となり、処理速度が低下してしまう可能性があります。
スレッド並列化で3分→3秒!本番環境で劇的な速度向上を実現
この記事では、Parallel.map によるプロセス並列化の落とし穴と、in_threads によるスレッド並列化で3分→3秒という劇的な速度向上を実現した体験談をご紹介します。
Parallel.mapによるプロセス並列化の落とし穴
ローカル環境では、Parallel.map を使用して4つのスレッドで処理を行ったところ、処理時間は約30秒と高速でした。しかし、本番環境では2つのコアに対して4つのプロセスを立ち上げたため、プロセスの立ち上げコストが処理時間の大部分を占め、結果的に3分もかかってしまうという問題が発生しました。
in_threadsによるスレッド並列化で劇的な速度向上
そこで、Parallel.map の代わりに in_threads を使用してスレッド並列化を試みたところ、処理時間はなんと3秒まで劇的に短縮されました。
in_threadsでプロセス並列化と比べて、プロセスの立ち上げコストが発生しないため、アクセス数の多い本番環境においては圧倒的なパフォーマンスを発揮します。
スレッドとプロセスの違い
1. 概要
スレッドとプロセスは、どちらもプログラムの実行単位ですが、異なる概念です。
プロセス: 独立した実行環境を持つプログラムの実行単位。メモリ空間、ファイルハンドル、CPU時間などのリソースを個別に所有します。
スレッド: 同じプロセス内で動作する軽量な実行単位。メモリ空間やファイルハンドルなどはプロセスと共有しますが、CPU時間などは個別に割り当てられます。
2. 主な違い
項目プロセススレッドリソース独立共有スケジュールOSアプリケーションコンテキストスイッチ重い軽いメモリ使用量大きい小さい実行速度遅い速い
3. それぞれの特徴
3.1 プロセスの特徴
独立した実行環境を持つため、高い安定性とセキュリティを実現できます。
複数のプロセスを同時に実行することで、マルチタスクを実現できます。
ただし、リソースの消費量が多いため、メモリやCPUリソースに制限がある環境では使いにくいです。
3.2 スレッドの特徴
プロセスと比べてリソースの消費量が少ないため、メモリやCPUリソースに制限がある環境でも使いやすいです。
同じプロセス内の複数のスレッドが同時に実行されるため、処理速度を向上させることができます。
ただし、データ競合などの問題が発生する可能性があります。
4. 使い分け
処理速度を重視する場合: スレッド
安定性とセキュリティを重視する場合: プロセス
リソースに制限がある場合: スレッド
まとめ
Parallel.map は手軽に並列処理を行える便利なライブラリですが、デフォルトでプロセス並列化を行うため、本番環境では思わぬ落とし穴にはまる可能性があります。
アクセス数の多い本番環境で並列処理を行う場合は、in_threads によるスレッド並列化を検討することで、劇的な速度向上が期待できます。