1つのスレッドとステートマシンのみを使用して、Javaなどの高級言語でマルチスレッド機能を実現するにはどうすればよいですか?たとえば、実行する2つのアクティビティ(計算とI / Oの実行)があり、1つのアクティビティがブロックできる場合はどうなりますか?
あなたが説明しているものは、協調マルチタスクと呼ばれ、タスクにCPUが与えられ、自己決定した時間またはアクティビティの後に自発的にCPUを放棄することが期待されます。CPUの使用を継続したり、作品全体をブロックしたりしてハードウェアウォッチドッグタイマーを持たないことで連携しないタスクは、タスクを監視するコードがそれに対してできることは何もありません。
最近のシステムで見られるものは、プリエンプティブマルチタスクと呼ばれます。これは、ハードウェア生成の割り込みが到着したときにスーパーバイザーがCPUを放棄するため、タスクがCPUを放棄する必要がない場所です。スーパーバイザの割り込みサービスルーチンは、CPUの状態を保存し、次にタスクがタイムスライスに値すると見なされるときにそれを復元し、次に実行されるタスクから状態を復元し、何も起こらなかったようにそこにジャンプします。このアクションはコンテキストスイッチと呼ばれ、コストがかかる場合があります。
高レベル言語でのマルチスレッドの代わりに、「ステートマシンのみ」の方法を使用できるのでしょうか。
実行可能ですか?確かに。正気?時々。スレッドを使用するか、何らかの形の自作の協調マルチタスク(ステートマシンなど)を使用するかは、実行するトレードオフに依存します。
スレッドは、タスクの設計を単純化して、データスペースを他のユーザーと共有する独自のプログラムとして処理できるようにします。これにより、一度に繰り返し作業を行うために必要な管理やハウスキーピングのすべてではなく、手元の仕事に集中することができます。しかし、善行は罰せられないので、コンテキストスイッチでこの便利さのすべてを支払います。最小限の作業(自発的に、またはI / Oなどのブロックを行うこと)を行った後、CPUを生成するスレッドが多数あると、コンテキストの切り替えを行うプロセッサ時間が大量に消費されます。これは、ブロッキング操作が非常に長い間ほとんどブロックされない場合に特に当てはまります。
協力的なルートがより理にかなっている状況がいくつかあります。私はかつて、ポーリングを必要とするメモリマップインターフェイスを通じて多くのデータチャネルをストリーミングするハードウェア用のユーザーランドソフトウェアを作成する必要がありました。すべてのチャネルは、スレッドとして実行するか、単一のポーリングサイクルを繰り返し実行できるように構築されたオブジェクトでした。
マルチスレッドバージョンのパフォーマンスは、上記で説明したとおりの理由でまったく良くありませんでした。各スレッドは最小限の作業を行ってからCPUを譲り、他のチャネルに時間がかかるため、多くのコンテキストスイッチが発生しました。スレッドがプリエンプトされるまで無料で実行するとスループットが向上しますが、タイムスライスをすぐに取得できなかったため、ハードウェアでバッファーオーバーランが発生する前に一部のチャネルが処理されなくなりました。
各チャネルを繰り返し実行するシングルスレッドバージョンは、やけどした猿のように実行され、システムの負荷は岩のように低下しました。追加のパフォーマンスに対して支払ったペナルティは、タスクを自分で調整しなければならなかったことです。この場合、それを行うためのコードは十分に単純であり、開発と保守のコストはパフォーマンスを改善する価値があります。それが本当に一番下の行だと思います。私のスレッドが、システムコールが戻るのを待っているスレッドだったとしたら、おそらくそれだけの価値はなかったでしょう。
Coxのコメントを読んでください。スレッドは、ステートマシンを作成できない人専用ではありません。一部の人々はそれを非常に行うことができますが、ジョブをより早く、またはより複雑にしないために、缶詰のステートマシン(つまり、スレッド)を使用することを選択します。