1. ホーム
  2. c#

[解決済み】非同期プログラミングとマルチスレッドの違いは何ですか?

2022-03-25 19:47:59

質問

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

非同期メソッドは、ノンブロッキング操作を意図しています。await 非同期メソッド内の式は、そのメソッドが実行されている間、現在のスレッドをブロックしません。 待ちのタスクは実行中です。その代わり、この式は残りのタスクにサインアップします。 を継続させ、制御を呼び出し元に戻します。 非同期メソッド

async および await キーワードは、追加のスレッドを発生させません。 を作成します。非同期メソッドはマルチスレッドを必要としません。 メソッドはそれ自身のスレッドで実行されません。このメソッドは現在の 同期コンテキストを使用し、そのスレッド上の時間を使用するのは メソッドがアクティブであることを示します。Task.Runを使えば、CPUに負荷のかかる作業を しかし、バックグラウンドスレッドでは、プロセス のように、結果が出るのを待つだけになってしまいます。

を、どなたか英語に訳していただけないでしょうか。非同期性(という言葉があるのか)とスレッドを区別して、非同期タスクがあってもマルチスレッドがないプログラムもあるということを暗示しているように思えます。

Jon Skeetの467ページの例のような非同期タスクの考え方が理解できるようになりました。 C#徹底攻略 第3版

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() とは何の関係もない。 x または y が発生します。 DisplayWebsiteLength() のように、バックグラウンドで実行されます。

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

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

(また、なぜ sendere は、上記の関数本体では決して使われません)。

どのように解決するのですか?

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

通常、例えが役に立ちます。 あなたはレストランで料理をしています。卵とトーストの注文が入りました。

  • 同期:卵を焼き、次にトーストを焼く。
  • 非同期、シングルスレッド:卵の調理を開始し、タイマーをセットします。トーストの調理を開始し、タイマーをセットする。両方の調理中に、キッチンを掃除する。タイマーが鳴ったら、卵を火から下ろし、トーストをトースターから出して、料理を提供します。
  • 非同期、マルチスレッド:さらに2人のコックを雇い、1人は卵を、1人はトーストを焼くようにします。今度は、キッチンでリソースを共有するときに、料理人同士が衝突しないように調整する問題があります。そして、彼らに給料を払わなければなりません。

さて、マルチスレッドは非同期の一種に過ぎないというのは、意味があるのでしょうか? スレッディングはワーカーのこと、非同期はタスクのこと . マルチスレッドワークフローでは、ワーカーにタスクを割り当てる。非同期シングルスレッドワークフローでは、いくつかのタスクは他のタスクの結果に依存しており、各タスクが完了すると、完了したばかりのタスクの結果を考慮して、次に実行できるタスクをスケジュールするコードが呼び出されます。しかし、(できれば)すべてのタスクを実行するのに必要なワーカーは1つだけでよく、タスクごとにワーカーが必要なわけではありません。

多くのタスクは、プロセッサに依存しないことを理解するのに役立つでしょう。プロセッサ束縛型のタスクでは、プロセッサの数だけワーカー(スレッド)を雇い、各ワーカーに1つのタスクを割り当て、各ワーカーに1つのプロセッサを割り当て、各プロセッサには結果をできるだけ速く計算する以外の仕事をさせることが理にかなっています。しかし、プロセッサを待たないタスクの場合は、ワーカーを割り当てる必要はまったくない。あなたはただ、結果が利用可能であるというメッセージが届くのを待ち、そして 待っている間に他のことをする . そのメッセージが届いたら、完了したタスクの続きを、ToDoリストの次のチェック項目としてスケジュールすることができます。

では、Jonの例をもう少し詳しく見てみましょう。 どうなるのでしょうか?

  • 誰かが DisplayWebSiteLength を呼び出した。誰が? 私たちは気にしません。
  • ラベルを設定し、クライアントを作成し、クライアントに何かを取得するように依頼します。クライアントは、何かを取得するタスクを表すオブジェクトを返します。そのタスクは進行中です。
  • 別のスレッドで進行中なのでしょうか?おそらく違います。読む スティーブンの記事 なぜスレッドがないのかについて。
  • では、タスクを待ちます。何が起こるのでしょうか?タスクを作成してから待機するまでの間に、そのタスクが完了したかどうかを確認します。もしイエスなら、結果をフェッチして実行を継続します。タスクが完了しなかったとしましょう。 このメソッドの残りをそのタスクの継続としてサインアップし、次のように返します。 .
  • これで制御が呼び出し元に戻りました。それは何をするのでしょうか?好きなようにします。
  • さて、このタスクが完了したとします。どうやって完了したのでしょうか?別のスレッドで実行されていたのかもしれませんし、先ほど戻した呼び出し元が現在のスレッドで完了まで実行することを許可していたのかもしれません。いずれにせよ、私たちは今、完了したタスクを手にしています。
  • 完了したタスクは、正しいスレッドに問い合わせます -- ここでもおそらく のみ スレッドにタスクの継続を実行させる。
  • awaitの時点で残したメソッドに、すぐに制御が戻ってきます。ここで の結果が利用可能なので text を実行し、残りのメソッドを実行します。

私の例え話と同じです。誰かがあなたに書類を要求してきました。あなたはその書類を郵便で送りますが、他の仕事を続けなければなりません。郵便物が届いたら合図があり、気が向いたら残りのワークフロー、つまり封筒を開けたり、配達料を支払ったりします。封筒を開けたり、配達料を支払ったり、残りの作業をする必要がないのです。