我如何 运行 并行执行任务并 select 在 C# 中满足给定条件的第一个结果?

How do I run tasks in parallel and select the first result that satisfies a given condition in C#?

我希望 运行 同时执行三个任务。我想检查完成的第一个任务的结果,并进行检查以确定结果是否 good。如果是,我取消所有其他任务和 return 这个结果,如果不是,我将等待下一个完成的任务并检查它是否 good 如果是则执行相同的操作. (将 good 视为对 OutputDataType 成员的一些简单检查)。

我会继续这样做,直到我获得一个完成的任务 good,或者所有任务 return 结果不 good, 在这种情况下我 return 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));

            /*
            .
            .
            .
            */
        }
    }
}

在 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;
}

根据 Spo1ler 的评论,我已将您的 Foo 方法更新为异步实现。这假设您使用的是 C# 5.0。使用该方法时,使用 await 获取其结果。如果你真的 运行 作为控制台应用程序,你的最上面的调用将需要阻塞,所以你可以只获取任务的 Result.