我如何 运行 并行执行任务并 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
.
我希望 运行 同时执行三个任务。我想检查完成的第一个任务的结果,并进行检查以确定结果是否 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
.