非同期プログラミングとマルチスレッドの違いは何ですか? 質問する

非同期プログラミングとマルチスレッドの違いは何ですか? 質問する

私は、それらは基本的に同じことだと思っていました。つまり、2つ以上のプロセッサを持つマシンでプロセッサ間でタスクを分割するプログラムを書くことです。これそこにはこう書かれています。

非同期メソッドは、非ブロッキング操作を目的としています。非同期メソッド内の await 式は、待機中のタスクの実行中に現在のスレッドをブロックしません。代わりに、式はメソッドの残りの部分を継続として登録し、非同期メソッドの呼び出し元に制御を返します。

async および await キーワードによって追加のスレッドが作成されることはありません。非同期メソッドは独自のスレッドで実行されないため、マルチスレッドは必要ありません。メソッドは現在の同期コンテキストで実行され、メソッドがアクティブな場合にのみスレッドで時間を使用します。Task.Run を使用して CPU バインド作業をバックグラウンド スレッドに移動できますが、バックグラウンド スレッドは結果が使用可能になるまで待機しているプロセスには役立ちません。

どなたかこれを英語に翻訳していただけないでしょうか。非同期性 (これは単語でしょうか?) とスレッドを区別し、非同期タスクを持ちながらマルチスレッドを持たないプログラムを作成できることを暗示しているようです。

今では、Jon Skeet のC# In Depth、第 3 版の467 ページにある例のような非同期タスクの考え方を理解しています。

async void DisplayWebsiteLength ( object sender, EventArgs e )
{
    label.Text = "Fetching ...";
    using ( HttpClient client = new HttpClient() )
    {
        Task<string> task = client.GetStringAsync("http://csharpindepth.com");
        string text = await task;
        label.Text = text.Length.ToString();
    }
}

キーワードasyncは、「この関数は、呼び出されるたびに、その呼び出し後のすべての呼び出しにその完了が必要となるコンテキストでは呼び出されません。」を意味します。

つまり、何かの作業の途中で書く

int x = 5; 
DisplayWebsiteLength();
double y = Math.Pow((double)x,2000.0);

はや とはDisplayWebsiteLength()関係がないので、は「バックグラウンド」で実行されます。xyDisplayWebsiteLength()

                processor 1                |      processor 2
-------------------------------------------------------------------
int x = 5;                                 |  DisplayWebsiteLength()
double y = Math.Pow((double)x,2000.0);     |

明らかにそれは愚かな例ですが、私の考えは正しいでしょうか、それとも完全に混乱しているのでしょうか?

(また、上記の関数の本体でsenderとが使用されない理由についても混乱しています。)e

ベストアンサー1

あなたの誤解は非常に一般的です。多くの人は、マルチスレッドと非同期は同じものだと教えられていますが、そうではありません。

類推が役に立つことが多いです。あなたはレストランで料理をしています。卵とトーストの注文が入りました。

  • 同期: 卵を調理してからトーストを調理します。
  • 非同期、シングルスレッド: 卵の調理を開始し、タイマーを設定します。トーストの調理を開始し、タイマーを設定します。両方が調理されている間に、キッチンを掃除します。タイマーが鳴ったら、卵を火から下ろし、トーストをトースターから取り出して提供します。
  • 非同期、マルチスレッド: 卵を調理する料理人とトーストを調理する料理人をそれぞれ 2 人雇います。ここで問題となるのは、キッチンでリソースを共有するときに料理人が衝突しないように調整することです。また、料理人に給料を支払う必要があります。

マルチスレッドは非同期の一種にすぎないというのは、理にかなっていますか?スレッドはワーカーに関するもので、非同期はタスクに関するものです。マルチスレッド ワークフローでは、タスクをワーカーに割り当てます。非同期のシングルスレッド ワークフローでは、一部のタスクが他のタスクの結果に依存するタスクのグラフがあります。各タスクが完了すると、完了したばかりのタスクの結果に基づいて、実行可能な次のタスクをスケジュールするコードが呼び出されます。ただし、すべてのタスクを実行するには、(うまくいけば) 1 つのワーカーだけが必要であり、タスクごとに 1 つのワーカーは必要ありません。

多くのタスクはプロセッサにバインドされていないことを理解すると役に立ちます。プロセッサにバインドされたタスクの場合、プロセッサと同じ数のワーカー (スレッド) を採用し、ワーカーごとに 1 つのタスクを割り当て、ワーカーごとに 1 つのプロセッサを割り当て、各プロセッサに結果をできるだけ早く計算する以外の作業を行わせるのが合理的です。ただし、プロセッサを待機していないタスクの場合、ワーカーを割り当てる必要はありません。結果が利用可能であるというメッセージが到着するのを待ち、待っている間に他の作業を行うだけです。そのメッセージが到着したら、完了したタスクの継続を、ToDo リストの次のチェック項目としてスケジュールできます。

それでは、ジョンの例を詳しく見てみましょう。何が起こるでしょうか?

  • 誰かが DisplayWebSiteLength を呼び出します。誰が? 私たちには関係ありません。
  • ラベルを設定し、クライアントを作成し、クライアントに何かを取得するように要求します。クライアントは何かを取得するタスクを表すオブジェクトを返します。そのタスクは進行中です。
  • 別のスレッドで進行中ですか?おそらくそうではないでしょう。スティーブンの記事なぜスレッドがないのかについて。
  • ここで、タスクを待機します。何が起こるでしょうか? タスクを作成してから待機するまでの間にタスクが完了したかどうかを確認します。完了している場合は、結果を取得して実行を続けます。完了していないと仮定します。このメソッドの残りの部分をそのタスクの継続として登録し、 を返します
  • これで制御が呼び出し元に戻ります。呼び出し元は何をするでしょうか? 呼び出し元が望むことなら何でもします。
  • ここで、タスクが完了したとします。どのようにして完了したのでしょうか。別のスレッドで実行されていたか、または、戻った呼び出し元が現在のスレッドで完了するまで実行を許可した可能性があります。いずれにせよ、これでタスクは完了しました。
  • 完了したタスクは、正しいスレッド (おそらく唯一のスレッド) にタスクの続きを実行するように要求します。
  • 制御は、待機の時点で終了したメソッドにすぐに戻ります。これで結果が利用できるようになったので、メソッドの残りの部分を割り当てtext実行できます。

それはまさに私の例えと同じです。誰かがあなたに書類を要求します。あなたはその書類を郵送して、他の作業を続けます。その書類が郵便で届いたら通知が届き、気が向いたら残りのワークフローを実行します。封筒を開けたり、配送料を支払ったり、その他何でも。あなたの代わりにその作業を行う別の作業員を雇う必要はありません。

おすすめ記事