質問
非同期処理の基本的な考え方の話なのですが、asyncメソッドを使用した時のawaitとResultの違いは両方処理が終わるのは待つがメインスレッドが止まるか止まらないかの違いということでよいのですか。
C#
1async void hoge(){ 2 string s=await fuga(); 3}
C#
1void hoge(){ 2 string s=fuga().Result; 3}
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2020/09/19 00:05 編集
回答1件
0
ベストアンサー
質問への私のコメント、
何を作っているか書きましょう。コンソールアプリと Windows Forms では話が違ってきます。時にあなたが気にしている「メインスレッドが止まるか止まらないか」というところ。
fuga の中身を書いてください。
・・・に返事がないのではっきりしませんが、「メインスレッドが止まるか止まらないか」を気にしているということは多分 Windows Forms のような GUI アプリで、fuga は Task<string> を返す以下のようなメソッドであろうと想像してレスします。
private async Task<string> fuga() { await Task.Delay(3000); return "戻り値"; }
asyncメソッドを使用した時のawaitとResultの違いは両方処理が終わるのは待つがメインスレッドが止まるか止まらないかの違いということでよいのですか。
前者の async / await を使った方は await で fuga の処理が終わるのを待ちますがメッセージループは処理されるので GUI はフリーズしません。それはたぶん質問者さんが期待する動きになると思います。
しかし、質問者さんのコードの後者の Task.Result を使った方はデッドロックになると思います。
「思います」と言うだけでは説得力がないので、Windows Forms アプリで以下のコードを書いて検証してみました。コメントにデッドロックと書いた方(質問者さんの例では後者の方)はデッドロックになります。
using System; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsAsyncTest { public partial class Form3 : Form { public Form3() { InitializeComponent(); } // デッドロック // Task.Result プロパティの get アクセサーにアクセスすると // 非同期操作が完了するまで呼び出し元のスレッドがブロックされる。 // これは、Wait メソッドを呼び出すことと同じ private void button1_Click(object sender, EventArgs e) { label1.Text = ""; string str = TimeCosumingMethod().Result; label1.Text = str; } // 正常動作 private async void button2_Click(object sender, EventArgs e) { label1.Text = ""; string str = await TimeCosumingMethod(); label1.Text = str; } private async Task<string> TimeCosumingMethod() { await Task.Delay(3000); return "TimeCosumingMethod の戻り値"; } } }
その理由については以下の記事の「図 3 非同期コードをブロックする際によくあるデッドロックの問題」のセクションが参考になると思います。
非同期プログラミングのベスト プラクティス
https://docs.microsoft.com/ja-jp/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming
ちなみに、上の記事に書いてある通り、コンソールアプリであればデッドロックにはなりません。以下のコードで確認しました。
using System; using System.Threading.Tasks; using System.Threading; namespace ConsoleAppAsync3 { class Program { static async Task Main(string[] args) { Console.WriteLine("Main のはじまり " + Thread.CurrentThread.ManagedThreadId); string str1 = await TimeCosumingMethod(); Console.WriteLine(str1); string str2 = TimeCosumingMethod().Result; Console.WriteLine(str2); Console.WriteLine("Main のおわり " + Thread.CurrentThread.ManagedThreadId); } static async Task<string> TimeCosumingMethod() { Console.WriteLine("TimeCosumingMethod はじまり " + Thread.CurrentThread.ManagedThreadId); await Task.Delay(3000); Console.WriteLine("TimeCosumingMethod おわり " + Thread.CurrentThread.ManagedThreadId); return "TimeCosumingMethod の戻り値 " + Thread.CurrentThread.ManagedThreadId; } } }
結果は:
投稿2020/09/19 04:20
編集2020/09/19 07:40退会済みユーザー
総合スコア0
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。