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

纵饮孤独 提交于 2019-12-30 07:03:08

问题


There are three tasks that I wish to run in parallel. I wish to examine the result of the first task that finished and do a check to decide if the result is good. If yes, I cancel all other tasks and return this result, if not, I will wait for next completed task and check if that is good and do the same if it is. (Think of being good as some simple check on a member of OutputDataType).

I continue this until I obtain a completed task with a good result, or all tasks return with results that are not good, in which case I return null.

Thank you in advance.

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));

            /*
            .
            .
            .
            */
        }
    }
}

回答1:


In TPL, task cancellation is cooperative, so you need to define some means of indicating to your other tasks that they should stop executing. The most common way to do this is through CancellationTokenSource, whose token can be checked for cancellation within your RunFuncX methods.

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

Per Spo1ler's comment, I've updated your Foo method to an asynchronous implementation. This assumes you're using C# 5.0. When consuming the method, use await to get its result. If you're really running as a console application, your topmost call would need to block, so you can just get the task's Result.



来源:https://stackoverflow.com/questions/28840019/how-do-i-run-tasks-in-parallel-and-select-the-first-result-that-satisfies-a-give

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!