2

私は、データをできるだけ早くシリアルプロセスに戻すことが重要であるアプリケーションに取り組んでいますが、そのデータを取得するソースは複数存在する可能性があります。また、一方のソースがもう一方のソースよりも高速である場合もありますが、どのソースになるかはわかりません。続行して呼び出し元のメソッドから戻るために、ContinueWhenAny(...)。Wait()を使用して最初のタスクが終了するのを待ちます。ただし、最初にデータの有効性を確認してから戻る必要があります(または、すべてのタスクが終了し、有効なデータがない場合)。今のところ、それが最初に終了するタスクである場合、私のコードは無効なデータも返します。

「ContinueWhenAny」のようなことを行う方法はありますが、Task.Resultが特定の条件を満たす場合にのみ、それ以外の場合は、最後のタスクが終了するまで次のタスクなどを待ちますか?

同様に、1つの結果が有効になった後、他のスレッドがキャンセルされることを確認する必要があります。この部分はすでに正常に機能しています。

現在、私のコードは次のようになっています(例外処理が削除され、要点だけが削除されています)。

        ResultObject result = null;
        var tokenSource = new CancellationTokenSource();
        var tasks = listOfSources
                .Select(i => Task.Factory.StartNew(
                    () =>
                        {
                            i.CancellationToken = tokenSource.Token;
                            //Database Call
                            return i.getData(inputparameters);
                        }, tokenSource.Token));

        Task.Factory.ContinueWhenAny(
                tasks.ToArray(),
                firstCompleted =>
                    {
                        //This is the "result" I need to validate before setting and canceling the other threads
                        result = firstCompleted.Result;
                        tokenSource.Cancel();
                    }).Wait();
        return result;

何か案は?最初の呼び出しに2秒かかり、2番目の呼び出しに10秒かかる場合、最初の呼び出しが有効なデータを返す場合は2秒でシリアルプロセスに戻りたいので、ContinueWhenAllを使用したくありません。それ以外の場合は、10秒待ちます。結果には有効なデータがあり、すべてのタスクが完了して無効な結果を返した場合にのみ無効なデータを返します。

---------更新----素晴らしいアイデアをありがとうzmbq。更新された(動作する)コードは以下のとおりであり、私のすべての要件を満たしています。ただし、このコードと前のコードの違いは、無効な結果自体を返す前のコードではなく、どのタスクも有効な結果を生成しない場合、このコードはnullの結果を返すことです。このバージョンを変更するのも難しいことではありませんが、その場合は私の目的のためにnullを返すことに完全に満足しています。

        ResultObject result = null;
        var tokenSource = new CancellationTokenSource();
        var tasks = listOfSources
                .Select(i => Task.Factory.StartNew(
                    () =>
                        {
                            i.CancellationToken = tokenSource.Token;
                            //Database Call
                            return i.getData(inputparameters);
                        }, tokenSource.Token)).ToArray();

        result = GetFirstValidResult(tokenSource,tasks);

        return result;


   private ResultObject GetFirstValidResult(CancellationTokenSource tokenSource, Task<ResultObject>[] tasks)
    {
        ResultObject result = null;
        Task.Factory.ContinueWhenAny(
            tasks,
            firstCompleted =>
                {
                    var testResult = firstCompleted.Result;
                    if(testResult != null && testResult.IsValid())
                    {
                        result = testResult;
                        tokenSource.Cancel();
                    }
                    else
                    {
                        var remainingTasks = tasks.Except(new[]{firstCompleted}).ToArray();
                        if(remainingTasks.Any())
                        {
                            result = GetFirstValidResult(tokenSource, remainingTasks);
                        } 
                    }
                }).Wait();
        return result;
    }
4

1 に答える 1

4

そうですね、firstCompletedコールバックが結果をチェックし、結果が違法である場合に備えて残りのタスクでContinueWhenAnyを呼び出すと、完了です。

いつものように、 ZeroMQをご覧になることをお勧めします。タスクを起動し、結果が正当な場合は、各タスクにメッセージを出力キューに書き込ませます。メインスレッドはキューをブロックし、有効なメッセージがある場合、またはすべてのタスクがすでに終了した場合に戻ります。

于 2012-03-18T05:49:18.500 に答える