如何并行运行任务并选择满足C#中给定条件的第一个结果?

Con*_*Man 4 .net c# parallel-processing wait task-parallel-library

我希望并行运行三个任务.我希望检查完成的第一个任务的结果,并检查以确定结果是否良好.如果是,我取消所有其他任务并返回此结果,如果没有,我将等待下一个完成的任务并检查是否良好,如果是,则执行相同操作.(想想是良好的OutputDataType成员对一些简单的检查).

我继续这个,直到我获得一个结果很好的完成任务,或者所有任务返回的结果都不,在这种情况下我会返回null.

先感谢您.

using System;
using System.Threading;
using System.Threading.Tasks;
namespace myNamespace
{
    class Program
    {
        static void Main()
        {
            InputDataType data = getMyData();
            OutputDataType x = Foo(data);
        }   

        static OutputDataType Foo(InputDataType data)
        {
            Task<OutputDataType> task1 = null, task2 = null, taks3 = null;
            Task<OutPutDataType>[] TaskArray = { task1, task2, task3 };

            task1 = Task<SolutionInterpreters>.Factory.StartNew(() => RunFunc1(data));
            task2 = Task<SolutionInterpreters>.Factory.StartNew(() => RunFunc2(data));
            task3 = Task<SolutionInterpreters>.Factory.StartNew(() => RunFunc3(data));

            /*
            .
            .
            .
            */
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Dou*_*las 7

在TPL中,任务取消是合作的,因此您需要定义一些方法来向其他任务指示它们应该停止执行.最常见的方法是通过CancellationTokenSource,可以在RunFuncX方法中检查其令牌是否取消.

static void Main()
{
    InputDataType data = getMyData();
    OutputDataType x = Foo(data).Result;
}   

static async Task<OutputDataType> Foo(InputDataType data)
{
    // Spawn your tasks, passing the cancellation token.
    var cts = new CancellationTokenSource();
    var task1 = Task.Factory.StartNew(() => RunFunc1(data, cts.Token));
    var task2 = Task.Factory.StartNew(() => RunFunc2(data, cts.Token));
    var task3 = Task.Factory.StartNew(() => RunFunc3(data, cts.Token));
    var tasks = new [] { task1, task2, task3 };

    // Loop while tasks are running.
    while (tasks.Any())
    {
        // Wait for any task to complete.
        var completedTask = await Task.WhenAny(tasks);

        // If its result is good, indicate cancellation to the other tasks,
        // and return the result.
        if (IsResultGood(completedTask.Result))
        {
            cts.Cancel();
            return completedTask.Result;
        }

        // Otherwise, remove the completed task from the array,
        // and proceed to the next iteration.
        tasks = tasks.Where(t => t != completedTask).ToArray();
    }

    // No good results.
    return null;
}
Run Code Online (Sandbox Code Playgroud)

根据Spo1ler的评论,我已将您的Foo方法更新为异步实现.这假设您使用的是C#5.0.使用该方法时,用于await获取其结果.如果您真的是作为控制台应用程序运行,那么您的最顶层调用将需要阻止,因此您可以获得该任务Result.

  • 但是这段代码会阻止.从性能角度来看,使用`Task.WhenAny`并使其更有效地使用线程池是不是更好? (2认同)