2

私はこのコードを持っています:

    public async Task AsyncMethod()
    {
        await Task.Factory.StartNew(() =>
        {
            throw new Exception();
        });
    }

    public ActionResult Index()
    {
        var t1 = Task.Factory.StartNew(() => { throw new Exception(); });
        var t2 = Task.Factory.StartNew(() => { throw new Exception();});
        var t3 = Task.Factory.StartNew(async () => { await AsyncMethod(); });

        try 
        {
            Task.WaitAll(t1, t2, t3);
        }
        catch (AggregateException ex)
        {
            var count1 = ex.InnerExceptions.Count;
            var count2 = ex.Flatten().InnerExceptions.Count;

            throw;
        }

        return View();
    }

count1変数とcount2変数が3ではなく2である理由と、AsyncMethod内で3番目の例外を取得するにはどうすればよいですか?

4

2 に答える 2

3

これを変える

    var t3 = Task.Factory.StartNew(async () => { await AsyncMethod(); });

これに:

    var t3 = AsyncMethod();

すでにタスクあります。スレッドプールで実行してラップする必要はありません。

それをラップすることによって、Taskあなたはあなたがすでに持っている(そしてそれは最終的には失敗するでしょう)Task<Task>を決して失敗しない(そのTask.Result失敗だけ)に変換します。そしてWaitAllもちろん、外部タスクで動作するため、例外が発生することはありません。

このようなコードをデバッガーでステップ実行して、すべての変数の実行時の値を確認することをお勧めします。コードを見るだけでなく、この間違いに気付くのははるかに簡単です(これは経験があるので、「見る」だけで十分でしたが、経験がなかった場合は、このコードを実行してデバッグする必要がありました。それ)。

于 2012-12-31T13:41:32.757 に答える
3

count1変数とcount2変数が3ではなく2である理由と、AsyncMethod内で3番目の例外を取得するにはどうすればよいですか?

Task.Factory.StartNew基本を返しますTaskasyncデリゲートを渡すと、返さTaskれるのはメソッドの開始のみを表しますasync(呼び出し元に渡されるポイントまで)。

Task.Runコードで使用する必要がありasyncます。デリゲートのラッパーをTask.Run作成するため、から返されるfromはメソッド全体を表します。TaskasyncTaskTask.Runasync

Stephen Toubには、との違いを詳しく説明した優れたブログ投稿がTask.RunありTask.Factory.StartNewます。

また、usrが述べたように、GUIまたはASP.NETコンテキストでTaskはなく、ブロックするたびにデッドロックの問題が発生します。awaitこのデッドロックの問題について詳しく説明しているブログ投稿がありますawait Task.WhenAllの代わりに使用する必要がありTask.WaitAllます。

したがって、両方の変更が適用されたコードは次のとおりです。

public async Task AsyncMethod()
{
    await Task.Run(() =>
    {
        throw new Exception();
    });
}

public async Task<ActionResult> Index()
{
    var t1 = Task.Run(() => { throw new Exception(); });
    var t2 = Task.Run(() => { throw new Exception();});
    var t3 = Task.Run(async () => { await AsyncMethod(); });

    try 
    {
        await Task.WhenAll(t1, t2, t3);
    }
    catch (Exception)
    {
        var ex1 = t1.Exception.InnerException;
        var ex2 = t2.Exception.InnerException;
        var ex3 = t3.Exception.InnerException;

        throw;
    }

    return View();
}
于 2012-12-31T15:40:44.203 に答える