[解決済み】非同期処理の待ち時間、Wait()でプログラムがフリーズする原因はここにある
質問
前置き : 解決策だけでなく、説明を求めています。解決策はもう知っている。
タスクベース非同期パターン(TAP)、async、awaitに関するMSDN記事を数日かけて勉強したにもかかわらず、細かい部分でまだ少し混乱しています。
Windows Store Apps用のロガーを書いているのですが、非同期と同期の両方のロギングをサポートしたいのです。非同期メソッドはTAPに従いますが、同期メソッドはこれらをすべて隠して、普通のメソッドのように見え、動作する必要があります。
これが非同期ロギングのコアとなるメソッドです。
private async Task WriteToLogAsync(string text)
{
StorageFolder folder = ApplicationData.Current.LocalFolder;
StorageFile file = await folder.CreateFileAsync("log.log",
CreationCollisionOption.OpenIfExists);
await FileIO.AppendTextAsync(file, text,
Windows.Storage.Streams.UnicodeEncoding.Utf8);
}
では、それに対応するsynchronousメソッドを...
バージョン1 :
private void WriteToLog(string text)
{
Task task = WriteToLogAsync(text);
task.Wait();
}
これは正しく見えますが、うまくいきません。プログラム全体が永遠にフリーズしてしまいます。
バージョン2 :
うーん、もしかしてタスクが開始されていないのでは?
private void WriteToLog(string text)
{
Task task = WriteToLogAsync(text);
task.Start();
task.Wait();
}
これは、次のように投げます。
InvalidOperationException: Start may not be called on a promise-style task.
バージョン3です。
うーん...
Task.RunSynchronously
は期待できそうですね。
private void WriteToLog(string text)
{
Task task = WriteToLogAsync(text);
task.RunSynchronously();
}
これは、次のように投げます。
InvalidOperationException: RunSynchronously may not be called on a task not bound to a delegate, such as the task returned from an asynchronous method.
バージョン4(解決策)。
private void WriteToLog(string text)
{
var task = Task.Run(async () => { await WriteToLogAsync(text); });
task.Wait();
}
これはうまくいく。つまり、2と3は間違ったツールなのです。でも1は?1のどこが悪くて、4と何が違うの?1がフリーズする原因は何でしょうか?タスクオブジェクトに何か問題があるのでしょうか?明らかでないデッドロックがあるのでしょうか?
解決方法は?
その
await
非同期メソッドの内部では、UIスレッドに戻ろうとしています。
UIスレッドはタスク全体の完了を待つのに忙しいので、デッドロックが発生します。
非同期呼び出しを
Task.Run()
は問題を解決します。
非同期呼び出しがスレッドプールスレッドで実行されるようになったため、UIスレッドに戻ろうとせず、したがってすべてが動作します。
別の方法として
StartAsTask().ConfigureAwait(false)
内側の操作を待つ前に、UI スレッドではなくスレッドプールに戻ってくるようにし、デッドロックを完全に回避しています。
関連
-
[解決済み] エンティティタイプ ApplicationUser は、現在のコンテキストのモデルの一部ではありません。
-
[解決済み】C#におけるtypedefの等価性
-
[解決済み】Unity 「関連するスクリプトを読み込むことができません」「Win32Exception: システムは指定されたファイルを見つけることができません"
-
[解決済み】Entity FrameworkからのSqlException - セッション内で他のスレッドが動作しているため、新しいトランザクションは許可されません。
-
[解決済み】エラー「必要なフォーマルパラメータに対応する引数が与えられていない」を解決する?
-
[解決済み】ユーザー設定値を別のユーザー設定値で設定する
-
[解決済み] C#でawaitを使わずに非同期メソッドを安全に呼び出す方法
-
[解決済み】非同期プログラミングとマルチスレッドの違いは何ですか?
-
[解決済み】Task.Start/WaitとAsync/Awaitの違いは何ですか?
-
[解決済み】複数の非同期タスクを実行し、すべてのタスクが完了するのを待つ
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】WebForms UnobtrusiveValidationModeは、jqueryのScriptResourceMappingを必要とする
-
[解決済み] 保護レベルによりアクセス不能になりました。
-
解決済み] Critical error detected c0000374 - C++ dll returns pointer off allocated memory to C# [解決済み] Critical error detected c0000374 - C++ dll returns pointer off allocated memory to C#.
-
[解決済み】値が期待した範囲に収まらない
-
[解決済み】Visual studio 2019がデバッグ時にフリーズする件
-
[解決済み】Moqを使用してメソッド呼び出しを検証する
-
[解決済み] [Solved] .NETでスレッドの終了を待つには?
-
[解決済み】URLから画像をダウンロードする方法
-
[解決済み】Microsoft.Extensions.LoggingからILoggerを解決することができない
-
[解決済み】名前 'ViewBag' が現在のコンテキストに存在しない - Visual Studio 2015