2

次のコードがあります

var exceptions = new ConcurrentQueue<Exception>();
Task task = Task.Factory.StartNew(() =>
{
    try
    {
        Parallel.Invoke(
            async () => await _aViewModel.LoadData(_someId),
            async () => await _bViewModel.LoadData(_someId)
        );
    }
    catch (Exception ex)
    {
        exceptions.Enqueue(ex);
    }
}).ContinueWith((continuation) =>
    {
        if (exceptions.Count > 0) throw new AggregateException(exceptions);
    });

ここで Task.StartNew を使用しているのは、LoadData メソッドが Dispatcher.StartAsync メソッドを使用してメイン UI スレッドを内部的に呼び出すためです。

私が抱えている問題は、強制_aViewModel.LoadData的に例外をスローした場合、それが Catch(Exception) 句でキャッチされないことです (また、AggregateException をキャッチした場合も)。なぜだか分からない!?

4

2 に答える 2

4

Parallel.Invokeは認識していませasyncん。そのため、ラムダは非常に厄介なエラーセマンティクスを持つメソッドasyncに変換されています (メソッドを離れることは許可されていません。代わりに、メソッドが開始されたときにアクティブだった で直接キャプチャされ、再発生します。この場合) 、スレッドプール)。async voidasync voidSynchronizationContextasync void

そもそもなぜあなたが を持っているのかわかりませんParallel.Invoke。メソッドは既にasyncであるため、次のようなことができます。

Task task = Task.Factory.StartNew(async () =>
{
    try
    {
        Task.WaitAll(
            _aViewModel.LoadData(_someId),
            _bViewModel.LoadData(_someId)
        );
    }
    catch (Exception ex)
    {
        exceptions.Enqueue(ex);
    }
})...

PS 時間があれば、コードのこの部分全体の構造を再考してください。Dispatcher.StartAsyncコードの匂いです。UI は (非同期に) データを要求する必要があります。データ取得オブジェクトは、UI について知る必要はありません。

于 2013-11-05T18:32:06.640 に答える
3

Parallel.InvokeActionデリゲートの配列を取ります。デリゲートが実際にasyncメソッドであることを知る手段がないため、タスクが完了する前に戻ります。

この動作の詳細については、この件に関するLucian Wischik の Channel 9 ビデオをご覧ください。

代わりにTask.WhenAll メソッドを使用するようにコードを変更してみてください。

var aTask = _aViewModel.LoadData(_someId);
var bTask = _bViewModel.LoadData(_someId);
await Task.WhenAll(aTask, bTask);
于 2013-11-05T18:30:59.300 に答える