スレッドプール

待機中のタスク (青) と完了したタスク (黄色) を含むサンプル スレッド プール (緑のボックス)

コンピュータプログラミングにおいて、スレッドプールは、コンピュータプログラムで同時実行を実現するためのソフトウェア設計パターンです。複製ワーカーモデルワーカークルーモデルとも呼ばれ、[ 1 ]スレッドプールは、監視プログラムによって同時実行用に割り当てられるタスクを待機する複数のスレッドを維持します。スレッドのプールを維持することにより、このモデルはパフォーマンスを向上させ、短命タスクのスレッドの頻繁な作成と破棄によって生じる実行の遅延を回避します。[ 2 ]もう 1 つの優れた特性は、使用可能なスレッド数よりも少ないスレッド数を使用した場合に、システム負荷を制限できることです。使用可能なスレッドの数は、実行完了後の並列タスクキューなど、プログラムで使用可能なコンピューティングリソースに合わせて調整されます。

パフォーマンス

スレッドプールのサイズとは、タスク実行用に確保されるスレッドの数です。これは通常、アプリケーションの調整可能なパラメータであり、プログラムのパフォーマンスを最適化するために調整されます。[ 3 ]最適なスレッドプールサイズを決定することは、パフォーマンスを最適化する上で非常に重要です。

タスクごとに新しいスレッドを作成するよりもスレッドプールを使用する利点の1つは、スレッドの作成と破棄のオーバーヘッドがプールの初期作成時のみに限定されるため、パフォーマンスとシステムの安定性が向上する可能性があることです。スレッドとそれに関連するリソースの作成と破棄は、時間の面でコストのかかるプロセスになる可能性があります。ただし、予約されているスレッドの数が多すぎるとメモリが浪費され、実行可能なスレッド間のコンテキスト切り替えによってパフォーマンスが低下します。別のネットワークホストへのソケット接続は、切断と再確立に多くのCPUサイクルを要する場合がありますが、複数のネットワークトランザクションにわたって存続するスレッドに関連付けることで、より効率的に維持できます。

スレッドプールの使用は、スレッドの起動時間を別にしても有用である可能性があります。スレッドプールの実装の中には、手動でスレッドを管理するよりも簡単に、作業をキューに登録し、同時実行を制御し、より高いレベルでスレッドを同期することを可能にするものがあります。[ 4 ] [ 5 ] このような場合、使用によるパフォーマンス上のメリットは二次的なものとなる可能性があります。

通常、スレッドプールは単一のコンピュータ上で実行されます。しかし、スレッドプールは概念的にはサーバーファームと関連しており、マスタープロセス(それ自体がスレッドプールである場合もあります)が、異なるコンピュータ上のワーカープロセスにタスクを分散させることで、全体のスループットを向上させます。このアプローチは、驚異的並列問題に非常に適しています。

スレッド数は、アプリケーションの存続期間中、待機中のタスク数に基づいて動的に調整される場合があります。例えば、Webサーバーは、 Webページへのリクエストが大量に届いた場合にスレッドを追加し、リクエストが減少したときにスレッドを削除できます。スレッドプールを大きくすると、リソース使用量が増加するというデメリットがあります。スレッドの作成または削除のタイミングを決定するアルゴリズムは、全体的なパフォーマンスに影響を与えます。

  • スレッドを作成しすぎると、リソースが無駄になり、未使用のスレッドを作成するのに時間がかかります。
  • スレッドをあまり多く破棄すると、後で再度作成するときに時間がかかります。
  • スレッドの作成が遅すぎると、クライアントのパフォーマンスが低下する可能性があります (待機時間が長くなります)。
  • スレッドの破棄が遅すぎると、他のプロセスのリソースが不足する可能性があります。

言語で

bashでは、 xargs--max-procs/によって実装されます。たとえば、次のようになります。 -P

# 5 つの URL を並列で取得しますurls =( "https://example.com/file1.txt" "https://example.com/file2.txt" "https://example.com/file3.txt" "https://example.com/file4.txt" "https://example.com/file5.txt" )printf '%s\n' " ${ urls [@] } " | xargs -P 5 -I {} curl -sI {} | grep -i "コンテンツの長さ:"

[ 6 ] [ 7 ] [ 8 ]

Goでは、ワーカープールと呼ばれます:

パッケージメインインポート( "fmt" "time" )func worker ( id int , jobs <- chan int , results chan < - int ) { for j := range jobs { fmt.Println ( " worker" , id , " started job" , j ) time.Sleep ( time.Second ) fmt.Println ( " worker " , id , " finished job " , j ) results <- j * 2 } }func main () { const numJobs = 5 jobs := make ( chan int , numJobs ) results := make ( chan int , numJobs )w : = 1 ; w <= 3 ; w ++ { go worker ( w , jobs , results ) }j := 1 ; j < = numJobs ; j ++ { jobs <- j } close ( jobs )a : = 1 ; a <= numJobs ; a ++ { <-結果} }

次のように印刷されます:

$ time go run worker-pools.goワーカー 1 がジョブ 1 を開始しましたワーカー 2 がジョブ2 を開始しました ワーカー3 がジョブ 3 を開始しましたワーカー 1 がジョブ 1 を終了しました ワーカー 1 がジョブ 4 を開始しました ワーカー 2がジョブ 2 を終了しましたワーカー 2 がジョブ 5 を開始しましたワーカー 3 がジョブ 3 を終了しましたワーカー 1 がジョブ 4 を終了しましたワーカー 2 がジョブ 5 を終了しました実数 0分2秒358秒

[ 9 ] [ 10 ] [ 11 ]

参照

参考文献

  1. ^ Garg, Rajat P. & Sharapov, Ilya「アプリケーションの最適化のためのテクニック - 高性能コンピューティングPrentice-Hall 2002」394 ページ
  2. ^ Holub, Allen (2000). Taming Java Threads . Apress. p. 209.
  3. ^ Yibei Ling; Tracy Mullen; Xiaola Lin (2000年4月). 「最適なスレッドプールサイズの分析」. ACM SIGOPS オペレーティングシステムレビュー. 34 (2): 42– 55. doi : 10.1145/346152.346320 . S2CID 14048829 . 
  4. ^ 「QThreadPool クラス | Qt Core 5.13.1」
  5. ^ 「GitHub - vit-vit/CTPL: 最新かつ効率的なC++スレッドプールライブラリ」 . GitHub . 2019年9月24日.
  6. ^ Shved, Paul (2010-01-07). 「LinuxでBashを使った簡単な並列化」 coldattic.info . 2025年1月26日閲覧
  7. ^ "xargs(1) - Linuxマニュアルページ" . www.man7.org . 2025年1月26日閲覧
  8. ^ 「並列処理の制御(GNU Findutils 4.10.0)」www.gnu.org . 2025年1月26日閲覧
  9. ^ 「Go by Example: ワーカープール」 . gobyexample.com . 2021年7月27日閲覧
  10. ^ 「Effective Go - The Go Programming Language」 . golang.org . 2021年7月27日閲覧リソースを効果的に管理する別の方法は、リクエストチャネルから読み取るハンドルゴルーチンを一定数起動することです。ゴルーチンの数によって、プロセスへの同時呼び出し回数が制限されます。
  11. ^ 「Goワーカープールの事例 — brandur.org」 . brandur.org . 2021年7月27日閲覧ワーカープールとは、固定数のm個のワーカー(Go言語のgoroutineで実装)が、ワークキュー(Go言語のチャネルで実装)内のn個のタスクを順番に処理していくモデルです。ワーカーが現在のタスクを終了して新しいタスクを引き継ぐまで、ワークはキューに留まります。