2012-04-01 4 views
24

「ユーザー空間」スレッドの実装に向けた多くのソリューションがあります。 golang.org goroutines、pythonの緑のスレッド、C#の非同期、erlangのプロセスなどです。アイデアは、単一のスレッドまたは限られた数のスレッドでも並行プログラミングを可能にすることです。OSスレッドが高価であると考えられるのはなぜですか?

私は理解できないことは、なぜOSスレッドが高価なのですか?私が見ているように、数十キロバイトのタスクスタック(OSスレッドまたはユーザランドスレッド)を保存しなければならず、2つのタスク間を移動するためにスケジューラが必要です。

OSは、この両方の機能を無料で提供します。なぜOSスレッドは "グリーン"スレッドよりも高価なはずですか?各「タスク」に対して専用のOSスレッドを持つことによって引き起こされると想定されるパフォーマンス低下の理由は何ですか?

+0

彼らは単に高価とはみなされません。私はいくつかの緑色のスレッド(ハスケルの?)はそれぞれわずか2キロバイトの重さ、すなわち100倍小さいと考えています。別の問題:標準的なPythonスレッドは緑色ではなく、GILによるマルチスレッドの問題がありますが、それでも実際のOSスレッドです(おそらく 'greenlets'を考えているのでしょうか?スレッド)。 – delnan

+0

@delnan OK、聞いたことがある。しかし、私はまだ彼らがより高価でなければならない理由は不明です。両方ともスタックを節約し、コンテキストスイッチを行う必要があります(GILを無視してください、多くの非Pythonの例があります)。 –

答えて

11

良い出発点であるチューダーズの答えを修正したい。スレッドの主なオーバーヘッドは2つあります:

  1. スレッドの開始と停止があります。スタックとカーネルオブジェクトの作成を行います。カーネルの移行とグローバルカーネルのロックを伴います。
  2. スタックの周りを維持する。

(1)は、常に作成して停止している場合にのみ問題になります。これはスレッドプールを使用して一般的に解決されます。私はこの問題が実際に解決されると考えています。スレッドプール上でタスクをスケジューリングするには、通常、カーネルへのトリップが含まれていないため、非常に速くなります。オーバーヘッドは、いくつかのインターロックされたメモリ操作のオーダーであり、いくつかの割り当てである。

(2)個のスレッド(> 100程度)がある場合にのみ、これは重要になります。この場合、async IOはスレッドを取り除く手段です。私はあなたがスレッドの狂気の量を持っていない場合、同期IOは、非同期IOより少し速いことがわかりました(あなたはその権利を読んでいます:同期IOは高速です)。

+1

(1)なぜカーネルオブジェクトがあなたがロックを必要とするユーザ空間オブジェクトよりも高価であるのかわかりません。すべてのロックはOS = kernleロックにまで沸きます。私は理解していない(2)あなたは彼らのスタックをとにかく保持する必要があります。 –

+0

未来/タスクがまだ実行を開始していない場合など、すべてのスレッドの代替がスタックを保持するわけではありません。また、OSスレッドスタックはより重くなります。 .NETスタックは常に1MBのメモリをコミットします(これは残念です)。 – usr

+2

(1)について:ロックはカーネルロックまで沸騰しません。非固定および/または短期ロックの多くの最適化が可能です。カーネルオブジェクトには、多くの理由でオーバーヘッドがあります(たとえば、プロセス間で共有でき、ACLを持つなど)。また、カーネルモードの移行が必要です。 – usr

4

小さなタスクごとにカーネルスレッドを開始する際の問題は、必要なスタックサイズと組み合わせて、起動と停止に無視できないオーバーヘッドが発生することです。

これは最初の重要な点です。スレッドプールは、スレッドのリサイクルを可能にするために存在し、スタックのメモリを無駄にするだけでなく、スレッドの開始に時間を浪費することもありません。

第2に、非同期I/Oを実行するスレッドを起動すると、ほとんどの時間がI/Oが完了するのを待ってブロックされるため、作業やメモリを無駄にしません。はるかに良いオプションは、単一のワーカーに複数の非同期コールを処理させることです(多重化などのいくつかのアンダーザフードスケジューリング手法によって)、メモリと時間を再度節約します。

「グリーン」スレッドをカーネルスレッドより速くすることの1つは、それらが仮想マシンによって管理されるユーザースペースオブジェクトであることです。それらを開始することはユーザー空間呼び出しですが、スレッドを開始することははるかに遅いカーネル空間呼び出しです。

+0

なぜそれにオーバーヘッドがあるのか​​分かりません。 "緑色の"スレッドとはどのように違うのですか?スタックを維持しなければならないので、同じ量のメモリを無駄にしています。 –

+1

@ Chi-Lan:「緑色の」スレッドは、実際のスレッドではなく、スレッドの抽象化である可能性があります。いくつかの緑のスレッドは、効率的な使用のために同じカーネルスレッド上でインテリジェントにスケジュールされています。たとえば、Windowsファイバーを使用して協調スケジューリングを行います。 – Tudor

+0

@ Chi-Lan:この問題を避けるために「緑色」/「軽量」スレッドが作成されています。これらの例はHaskell、Erlang、Pythonです。 –

0

私は2つのものが異なるレベルにあると思います。

ThreadまたはProcessは実行されているプログラムのインスタンスです。プロセス/スレッドには、もっと多くのものがあります。実行スタック、ファイル、信号、プロセッサーの状態、および他の多くのものを開く。

Greentletとは異なり、vmで動作します。軽量スレッドを提供します。それらの多くは擬似同時(通常は単一または少数のOSレベルのスレッドで)を提供します。そして、しばしば、データ共有の代わりにデータ送信によってロックフリーの方法を提供します。

したがって、2つの事柄が異なるので、重量が異なります。

私の考えでは、OSではなく、VMでグリーンレットを完成させるべきです。

+1

グリーンレットはVMなしでも可能です、golang.orgを参照してください –

6

「ユーザースペース」スレッドを実装するための多くのソリューションがあります。 golang.org goroutines、pythonの緑のスレッド、C#の非同期、erlangのプロセスなどです。アイデアは、単一のスレッドまたは限られた数のスレッドでも並行プログラミングを可能にすることです。

抽象レイヤーです。多くの人がこの概念を把握し、多くのシナリオでより効果的に使用する方が簡単です。多くの場合、モデルが幅から引っ張りに移動することが多いため、(良い抽象を前提とした)多くのマシンでは、より簡単です。 pthreads(例として)では、あなたはすべてのコントロールを持っています。他のスレッドモデルでは、スレッドを再利用して、並行タスクを安価に作成するプロセスと、まったく異なるスレッドモデルを使用するという考えがあります。このモデルを消化するのはずっと簡単です。学び、測定することが少なく、結果は一般的に良いです。

私は理解できませんが、なぜOSスレッドが高価なのですか?私が見ているように、数十キロバイトのタスクスタック(OSスレッドまたはユーザランドスレッド)を保存しなければならず、2つのタスク間を移動するためにスケジューラが必要です。

スレッドの作成にはコストがかかり、スタックにはメモリが必要です。また、プロセスが多くのスレッドを使用している場合、コンテキスト切り替えによってパフォーマンスが低下する可能性があります。したがって、軽量のスレッドモデルは、いくつかの理由で有用になりました。 OSスレッドの作成は、中規模から大規模のタスクに適したソリューションであり、理想的には少ない数です。それは制限的であり、維持にかなりの時間がかかります。

タスク/スレッドプール/ユーザランドスレッドは、コンテキストの切り替えやスレッドの作成の多くを心配する必要はありません。多くの場合、リソースが使用可能になった時点でリソースを再利用します(準備ができていない場合は、このマシンのアクティブなスレッドの数を決定します)。

多くのcommmonly(IMO)OSレベルのスレッドは、エンジニアによって正しく使用されていないため高価です - あまりにも多くあり、コンテキスト交換のトンがあるか、同じリソースセット、タスクが小さすぎます。 OSスレッドを正しく使用する方法と、プログラムの実行のコンテキストにその最適な方法を適用する方法を理解するのに、はるかに多くの時間がかかります。

OSは、この両方の機能を無料で提供します。

利用可能ですが、無料ではありません。それらは複雑であり、優れたパフォーマンスにとって非常に重要です。 OSスレッドを作成すると、すぐに時間が与えられます。すべてのプロセスの時間はスレッド間で分けられます。それはユーザースレッドの一般的なケースではありません。リソースが利用できない場合、タスクはしばしばエンキューされます。これにより、コンテキスト切り替え、メモリ、および作成するスレッドの総数が削減されます。タスクが終了すると、スレッドに別のスレッドが与えられます。

時間分布のこのアナロジー考えてみましょう:

  • は、あなたがカジノであると仮定します。カードを欲しい人がたくさんいます。
  • あなたには一定数のディーラーがいます。カードがほしい人よりもディーラーが少なくなっています。
  • いつでもすべての人に十分なカードがあるわけではありません。
  • ゲームやハンドを完了するためには、すべてのカードが必要です。ゲーム/ハンドが完了すると、カードはディーラーに返却されます。

どのようにディーラーにカードの配布を依頼しますか?

OSスケジューラでは、(スレッド)優先度に基づいています。すべての人に1度に1枚のカード(CPU時間)が与えられ、優先順位は継続的に評価されます。

人は、タスクまたはスレッドの作業を表します。カードは時間とリソースを表します。ディーラーはスレッドとリソースを表します。

ディーラー2人と3人がいれば、どのように最速で対処しますか? 5人のディーラーと500人の人がいたら?どのようにカードを使い果たすのを最小限に抑えることができますか?スレッドでは、カードの追加やディーラーの追加は、オンデマンドで提供できる解決策ではありません。 CPUを追加することは、ディーラーを追加することと同じです。スレッドを追加することは、一度に多くの人にカードを配布するディーラーと同じです(コンテキスト切り替えを増やす)。カードをより迅速に処理するための戦略は数多くあります。特に、特定の時間内に人々のカードが不要になった後は、ディーラーと人の比率が1/50だった場合、ゲームが完了するまで、テーブルに行って人や人に対処する方が速くないでしょうか?これを優先順位に基づいてすべてのテーブルに訪問し、すべてのディーラーの間で訪問を調整すること(OSアプローチ)と比較してください。それはOSが愚かであることを意味するものではない - OSスレッドの作成は、ディーラーが合理的に処理できるよりも多くの人とテーブルを追加するエンジニアであることを意味する。幸いにも、他のマルチスレッドモデルやより高い抽象化を使用することによって、多くの場合制約が解除される可能性があります。

OSスレッドが "グリーン"スレッドよりも高価になるのはなぜですか?各「タスク」に対して専用のOSスレッドを持つことによって引き起こされると想定されるパフォーマンス低下の理由は何ですか?

パフォーマンスに重大な低レベルスレッディングライブラリ(たとえばpthreads)を開発した場合、再利用の重要性が認識されます(ユーザーが利用できるモデルとしてライブラリに実装する)。この角度から、より高いレベルのマルチスレッドモデルの重要性は、実世界の使用法に基づいた単純で明白なソリューション/最適化であり、マルチスレッドを採用し、効果的に利用するためのエントリバーを下げることができるという理想です。

軽量スレッドのモデルとプールは、多くの問題に対してより優れたソリューションであり、スレッドをよく理解していないエンジニアにとってはより適切な抽象化です。このモデルでは、マルチスレッドの複雑さが大幅に簡素化されます(実際の使用ではより多くのパフォーマンスが向上します)。 OSスレッドでは、より多くの制御を行うことができますが、これらの考慮を考慮すると、プログラムの実行/実装を大幅に再開することができます。より高いレベルの抽象化では、これらの複雑さの多くは、タスク実行の流れを完全に変更することによって最小限に抑えられます(幅と引き数)。

6

スタックを保存するのは簡単です(スタックポインタをカーネルのスレッド情報ブロックに保存する必要があります)(大抵のレジスタも同様に保存されるため、ソフト/ハード割り込みによってOSが入力されました)。

1つの問題は、ユーザからカーネルに入るために保護レベルリングサイクルが必要であることです。これは本質的ですが、厄介なオーバーヘッドです。次に、ドライバまたはシステムコールは、割り込みによって要求されたものを実行してから、プロセッサへのスレッドのスケジューリング/ディスパッチを実行する必要があります。この結果、あるプロセスのスレッドが別のプロセスのスレッドによって先取りされた場合、余分なプロセスコンテキストの負荷も同様にスワップされる必要があります。 OSが、割り込みmutを処理しているプロセッサコア以外のプロセッサコアで実行されているスレッドがプリエンプトされていると判断した場合、さらにオーバーヘッドが追加されます。もう一方のコアはハードウェア割り込みが必要です(これはハード/最初の場所でOSをentred。

をので、スケジュール実行が非常に複雑操作であってもよい。

「グリーンスレッド」や「繊維」(通常)、あり、ユーザーコードからスケジュール。、コンテキストすべてのコンテキスト変更にWagnerianリングサイクルが必要でないため、プロセスコンテキストは変更されず、グリーンスレッドグループを実行するOSスレッドは変更されないため、OSの割り込みなどよりもはるかに簡単で安価です。

何かのための何かが存在しないので、緑のスレッドに問題があります。彼らは '本当の' OSスレッドで動作します。これは、1つのOSスレッドによって実行されるグループ内の1つの「緑色の」スレッドがブロックするOSコールを作成すると、グループ内のすべての緑色のスレッドがブロックされることを意味します。つまり、スリープ()のような単純な呼び出しは、他のグリーンスレッドにつながるステートマシンによって「エミュレート」されなければなりません(OSを再実装するのと同じです)。同様に、任意のスレッド間シグナリング。

もちろん、グリーンスレッドはIOシグナリングに直接応答することはできないため、最初にスレッドを持つ点をいくらか打ち負かします。

1

A person in Google shows an interesting approach.

彼によると、自分自身を切り替えるカーネルモードがボトルネックではなく、コアのコストは、SMPスケジューラに起こります。そして彼は、カーネルの助けを借りたM:Nスケジュールは高価ではないと主張しています。これによって、一般的なM:Nスレッドがあらゆる言語で利用できるようになります。

関連する問題