13

使用中に問題が発生し、スローされTask.Factory.StartNewた をキャプチャしようとしました。exception私のアプリケーションには、長時間実行されるタスクがあり、それをカプセル化したいと考えています。Task.Factory.StartNew(.., TaskCreationOptions.LongRunning);

ただし、を使用している場合、例外はキャッチされませんTask.Factory.StartNew。ただし、 を使用すると期待どおりに機能しますがTask.Run、これは単なるラッパーだと思っていましたTask.Factory.StartNew(たとえば、この MSDN の記事によると)。

実際の例をここに示します。違いは、 を使用する場合は例外がコンソールに書き込まれますが、 を使用する場合は書き込まれTask.RunませんFactory.StartNew

私の質問は次
のとおりです。例外をスローする可能性 のあるタスクがある場合LongRunning、呼び出し元のコードでそれらをどのように処理すればよいですか?

private static void Main(string[] args)
{
    Task<bool> t = RunLongTask();
    t.Wait();
    Console.WriteLine(t.Result);
    Console.ReadKey();
}

private async static Task<bool> RunLongTask()
{
    try
    {
        await RunTaskAsync();
    }
    catch (Exception e)
    {
        Console.WriteLine(e);
        return false;
    }
    Console.WriteLine("success");
    return true;
}

private static Task RunTaskAsync()
{
    //return Task.Run(async () =>
    //    {
    //        throw new Exception("my exception");
    //    });
    return Task.Factory.StartNew(
        async () =>
    {
        throw new Exception("my exception");
    });

}
4

3 に答える 3

16

あなたの問題は、デリゲートのようにStartNew機能しないことです。の戻りタイプは(に変換可能)です。「outer」はメソッドの開始を表し、「inner」はメソッドの完了(例外を含む)を表します。Task.RunasyncStartNewTask<Task>TaskTaskTask

内側に到達するにはTask、を使用できますUnwrap。または、コードTask.Runの代わりに使用することもできます。単なる最適化のヒントであり、実際にはオプションです。Stephen Toubは、との違いと、 (通常は)コードに優れている理由についての優れたブログ投稿をしています。StartNewasyncLongRunningStartNewRunRunasync

以下の@usrコメントからの更新: LongRunningメソッドの先頭にのみ適用されます(最初の不完全な操作が編集asyncされるまで)。したがって、この場合awaitに使用する方がほぼ確実に優れています。Task.Run

于 2013-02-06T13:07:09.233 に答える
2

私のコメントのいくつかを回答にまとめます。役立つことがわかったからです。

LongRunning実際に新しいスレッドを強制的に作成するのと同じです。そして、非同期メソッドはおそらくそのスレッド上に長い間ありません (最初の await ポイントで削除されます)。この場合、LongRunning は必要ありません。

非同期メソッドの実行時間は問題ではありません。スレッドは最初の await (完了していないタスクで動作する) で破棄されます。

コンパイラはこのヒントを何らかの方法で使用できますか? 通常、コンパイラは、主要な方法でコードを分析することはできません。また、コンパイラは TPL について何も知りません。TPL はライブラリです。そして、このライブラリは常に新しいスレッドを起動します。LongRunningタスクがほぼ常に 100% の CPU を数秒間消費するか、非常に高い確率で数秒間ブロックするかを指定します。

私の推測ではLongRunning、ブロックしている場合、そもそもなぜ非同期を使用しているのですか? 非同期は、ブロックするのではなく、スレッドから降りることです。

于 2013-02-06T14:02:09.883 に答える
0

最初にタスクをアンラップするときに可能になるはずです:

await RunTaskAsync().Unwrap();

または、次のようにします。

await await RunTaskAsync();
于 2013-02-06T13:29:17.403 に答える