我在 ASP.NET 控制台应用程序中有 8 个方法,例如
Fun1()
、Fun2()
、Fun3()
...等等。在我的控制台应用程序中,我按顺序调用了所有这些方法。但现在的要求是我必须使用并行编程概念来做到这一点。我读过 Java 中的任务和线程概念,但对 .NET 并行编程来说是全新的。
这是我在控制台应用程序中所需的方法流程,
如图所示,
Task1
和Task2
应该并行运行,而Task3
只会在前两个完成后才会发生。
每个任务中的函数(例如,
Fun3
和 Fun4
)应按顺序运行,一个接一个。有人可以帮我吗?
。 举个例子,我创建了 X 个名为 FuncX() 的方法,如下所示:
Task1
在本例中,我们有 Func1、Func3、Func4、Func5 和 Func6。
因此我们调用方法并将它们传递给任务列表。
async static Task<int> FuncX()
{
await Task.Delay(500);
var result = await Task.FromResult(1);
return result;
}
您有 2 个选择来获取结果:
var task1 = new List<Task<int>>();
task1.Add(Func3());
task1.Add(Func4());
var task2 = new List<Task<int>>();
task2.Add(Func1());
task2.Add(Func5());
task2.Add(Func6());
这只是灵感示例,您可以更改它并按照您想要的方式进行。
// option1
var eachFunctionIsDoneWithAwait1 = await Task.WhenAll(task1);
var eachFunctionIsDoneWithAwait2 = await Task.WhenAll(task2);
var sum1 = eachFunctionIsDoneWithAwait1.Sum() + eachFunctionIsDoneWithAwait2.Sum();
Console.WriteLine(sum1);
// option2
var task3 = new List<List<Task<int>>>();
task3.Add(task1);
task3.Add(task2);
var sum2 = 0;
task3.ForEach(async x =>
{
var r = await Task.WhenAll(x);
sum2 += r.Sum();
});
Console.WriteLine(sum2);
方法:
Task.Run
Task task1 = Task.Run(() =>
{
Fun3();
Fun4();
});
Task task2 = Task.Run(() =>
{
Fun1();
Fun5();
Fun6();
});
Task task3 = Task.Run(async () =>
{
await Task.WhenAll(task1, task2);
Fun7();
Fun8();
});
在
Task.Run
上调用委托,而不是在专用线程上。如果您出于某种原因需要为每个任务创建专用线程,则可以使用带有
ThreadPool
参数的高级 Task.Factory.StartNew
方法,如here所示。 需要注意的是,上述实现在出现异常时并不是最佳行为。如果
TaskCreationOptions.LongRunning
立即失败,最佳行为是尽快停止
Fun3()
的执行。相反,此实现将在传播错误之前执行所有三个函数 task2
、Fun1
和 Fun5
。您可以通过创建 Fun6
并在每个函数后调用
CancellationTokenSource
来修复这个小缺陷,但这会很混乱。另一个问题是,如果 Token.ThrowIfCancellationRequested
和
task1
都失败,则只有 task2
的异常才会通过 task1
传播。解决这个问题并非易事。
这是解决部分异常传播问题的一种方法:
task3
如果
Task task3 = Task.WhenAll(task1, task2).ContinueWith(t =>
{
if (t.IsFaulted)
{
TaskCompletionSource tcs = new();
tcs.SetException(t.Exception.InnerExceptions);
return tcs.Task;
}
if (t.IsCanceled)
{
TaskCompletionSource tcs = new();
tcs.SetCanceled(new TaskCanceledException(t).CancellationToken);
return tcs.Task;
}
Debug.Assert(t.IsCompletedSuccessfully);
Fun7();
Fun8();
return Task.CompletedTask;
}, default, TaskContinuationOptions.DenyChildAttach, TaskScheduler.Default)
.Unwrap();
和
task1
都失败,task2
将传播这两个任务的异常。