質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

2回答

1109閲覧

C#のasync,awaitについて

Yothuba3

総合スコア17

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2020/07/23 15:36

C#におけるasync,awaitの動作の仕方をあまりイメージできていないでいます。
聞きたい点

  • 非同期処理の流れ

質問

https://tech-lab.sios.jp/archives/15711
async,awaitを理解するために上記のサイトを参考に下のようなコードをサンプルとして用意してみました。

C#

1 class Program 2 { 3 static async Task Main(string[] args) 4 { 5 Task<string> task = HeavyMethod1(); 6 HeavyMethod2(); 7 Console.WriteLine(task.Result); 8 Console.ReadLine(); 9 } 10 11 static async Task<string> HeavyMethod1() 12 { 13 Console.WriteLine("すごく重い処理その1(´・ω・`)はじまり"); 14 await Task.Delay(5000); 15 Console.WriteLine("すごく重い処理その1(´・ω・`)おわり"); 16 17 for(int i = 0; i < 100; i++)//100秒ThreadSpeep 18 { 19 Thread.Sleep(1000); 20 Console.WriteLine(i + 1 + "秒経過"); 21 } 22 Console.WriteLine("すっごくまった"); 23 return "hoge"; 24 } 25 26 static void HeavyMethod2() 27 { 28 Console.WriteLine("すごく重い処理その2(´・ω・`)はじまり"); 29 Thread.Sleep(9000); 30 Console.WriteLine("すごく重い処理その2(´・ω・`)おわり"); 31 } 32 } 33} 34

処理の流れとして
1.HeavyMethod1(以下HM1)が実行される
2.await Task.Delay(5000)で非同期処理開始 メソッドを抜ける
3.HeavyMethod2(以下HM2)が実行される
4.HM2のスリープ中にHM1のDelayが完了する HM1に処理が移る
ここまでは理解できます。
ここで、4でHM1に処理が移ったあとに、HM1でawaitを使わずに同期的な重い処理
があった場合、その処理が終わるまでHM2はどうなるのだろうと思い、HM1に100秒スリープする処理を追加しています。
結果をいうと、3秒経過時点でHM2の「すごく~おわり」の出力が挟まれます。
その後に4秒経過,5秒経過と続いていきます。
予想では、非同期処理するのはawaitの行なのでそれ以外は同期処理すると思ったですが、
(つまり100秒経過後にHM2に処理が戻ると予想した)結果は違いました。
この結果をみると関数そのものが非同期で動いているような気がするのですが、
どなたかこのもやもやを解消する答えを頂けないでしょうか?
つたない文で申し訳ないです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2020/07/23 16:20

> この間、裏でメソッドAは実行中であり、メソッドAの実行が完了すると、再びメソッドAに処理が戻ります。 さっぱりわかりません。多分書いた人もわかっていません。その後の例示もひどいです。このサイトは参考にしないでください。
guest

回答2

0

ベストアンサー

Zuishin さんが質問のコメント欄で書かれている通り、参考にしている記事がよくないと思います。良くない最たるところは「非同期処理」と言いながら Main からは HeavyMethod1 も HeavyMethod2 も非同期呼び出ししてないところだと思います。

どう動いているかを以下のコードで調べてみました。コードの内容は ManagedThreadId を表示するようにしたことと、ループを 100 回から 10 回に減らした以外は質問のコードと同じです。

イメージ説明

上の画像の青枠部分のコードは HeavyMethod1 も HeavyMethod2 も非同期呼び出ししていません。赤枠部分の await Task.Delay(5000); も問題で、ここでスレッドが切り替わってしまいます。上のコードの事項結果は以下のようになります。各行の最後の数字が ManagedThreadId です。

イメージ説明

ちなみに、赤枠部分の await Task.Delay(5000); をコメントアウトすると実行結果は以下のようになります。ManagedThreadId が 1 で変わらないのが分かりますか。同期実行ですがこちらの方が質問者さんの望む結果に近いのでは?

イメージ説明

赤枠部分の await Task.Delay(5000); はそのままとしておき、HeavyMethod1 を非同期で実行してみます。上のコードの画像で青枠の部分をその下のコメントアウトしたコードと入れ替えて実行してみます。結果は以下のようになります。これも望む結果になっていないのでは?

イメージ説明

他のサンプルを探した方がよさそうな気がします。

投稿2020/07/24 02:53

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Yothuba3

2020/07/25 00:22

大変詳しく詳細を書いて頂きありがとうございます。 >>ManagedThreadId が 1 で変わらないのが分かりますか。同期実行ですがこちらの方が質問者さんの望む結果に近いのでは? 「処理その2 はじまり」が「処理その1 はじまり」の直後に出るものとして、実行されるスレッドのイメージに関してはまさにこのように予想していました.. つまるところ、僕が質問させていただいた「処理その2 おわり」の文が経過時間表示に割り込むのは、 HeavyMethod1の中で、await以降のコードも全て別スレッドで実行されているため、スレッド1で実行されているHavyMethod2に影響を与えないからという認識でよろしいでしょうか? そうなってしまう理由なども知りたいところですが、間違った理解の上でこういった質問をすると余計に理解を妨げる気がしてしまうので、改めてBluOxyさんに教えていただいた公式の解説などそういったもので、ある程度勉強して、また詰まったら質問してみようと思います..
退会済みユーザー

退会済みユーザー

2020/07/25 02:22

> つまるところ、僕が質問させていただいた「処理その2 おわり」の文が経過時間表示に割り込むのは、HeavyMethod1の中で、await以降のコードも全て別スレッドで実行されているため、スレッド1で実行されているHavyMethod2に影響を与えないからという認識でよろしいでしょうか? 自分的には、HeavyMethod1 の中の await Task.Delay(5000); によって結果的に(図らずも?)マルチスレッドプログラミングとなって HeavyMethod1 と HeavyMethod2 が別スレッドで実行されることになったから、各々独自に決められたタイミングで Console.WriteLine メソッドを実行した結果・・・と言った方がピンときます。
guest

0

この結果をみると関数そのものが非同期で動いているような気がするのですが、

その通りです。
await は、非同期メソッドの「完了を待ち」を行うための構文です。

投稿2020/07/23 23:36

hidori

総合スコア402

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問