gpt4 book ai didi

c# - 在前提完成之前继续运行

转载 作者:行者123 更新时间:2023-12-01 22:54:43 25 4
gpt4 key购买 nike

我有两个要执行的长时间运行的任务,然后继续执行。我遇到的问题是在两个长时间运行的任务发出信号之前继续运行。这两个任务没有出错,它们在继续开始时才刚刚开始。目的是前两个任务可以并行运行,但延续应该只在它们都完成后运行。

我可能忽略了一些非常简单的事情,但据我所知,我正在遵循问题 Running multiple async tasks and waiting for them all to complete 中建议的模式。 。我意识到我可能可以省去 .ContinueWith(),因为 Task.WhenAll() 之后的代码将隐式成为延续,但我更愿意保留显式延续(除非它是我的问题的原因)。

private async Task MyMethod()
{
var tasks = new List<Task>
{
new Task(async () => await DoLongRunningTask1()),
new Task(async () => await DoLongRunningTask2())
};

Parallel.ForEach(tasks, async task => task.Start());

await Task.WhenAll(tasks)
.ContinueWith(async t =>{
//another long running bit of code with some parallel
//execution based on the results of the first two tasks
}
, TaskContinuationOptions.OnlyOnRanToCompletion);

}

private async Task DoLongRunningTask1()
{
... long running operation ...
}

private async Task DoLongRunningTask2()
{
... another long running operation ...
}

感谢任何帮助或建议!

最佳答案

您的代码有多个问题:

  1. 使用非通用 Task 创建任务构造函数,带有 async代表。此构造函数接受 Action , 不是 Func<Task> ,所以你的异步委托(delegate)实际上是一个 async void ,即 something to avoid .您可以通过创建嵌套 Task<Task> 来解决此问题s,其中外部任务代表内部任务的启动。
  2. 使用Parallel.ForEach with async delegate .这再次导致 async void代表,出于同样的原因。当您想要并行化异步委托(delegate)时要使用的正确 API 是 Parallel.ForEachAsync ,可从 .NET 6 及更高版本获得。
  3. 使用并行机制启动任务。使用 Start 开始任务不受 CPU 限制。 Start不执行任务,它只是安排它执行,通常在 ThreadPool 上.所以你可以替换 Parallel.ForEach用一个简单的 foreach循环或 List.ForEach .
  4. 等待解包 ContinueWith具有 async 的延续代表。此延续返回一个嵌套的 Task<Task> .你应该 Unwrap 这个嵌套任务,否则您正在等待异步操作的启动,而不是它的完成。

这是您“修复”的代码:

private async Task MyMethod()
{
List<Task<Task>> tasksOfTasks = new()
{
new Task<Task>(async () => await DoLongRunningTask1()),
new Task<Task>(async () => await DoLongRunningTask2())
};

tasksOfTasks.ForEach(taskTask => taskTask.Start());

await Task.WhenAll(tasksOfTasks.Select(taskTask => taskTask.Unwrap()))
.ContinueWith(async t =>
{
//another long running bit of code with some parallel
//execution based on the results of the first two tasks
}, TaskContinuationOptions.OnlyOnRanToCompletion).Unwrap();
}

如果 DoLongRunningTask1 失败或 DoLongRunningTask2方法,此代码很可能会导致 TaskCanceledException ,这就是当您通过 TaskContinuationOptions.OnlyOnRanToCompletion 时发生的情况标志并且前面的任务没有成功运行到完成。这种行为不太可能是您想要的。

上面的代码也违反了指南CA2008: Do not create tasks without passing a TaskScheduler .该准则表示依赖环境 TaskScheduler.Current不是一个好主意,明确指定 TaskScheduler.Default被推荐。您必须在 Start 中指定它和 ContinueWith方法。

如果您认为所有这些都过于复杂,那您是对的。这不是您想要编写和维护的代码类型,除非您已经花费数月时间研究任务并行库,您对它了如指掌,并且没有其他更高级别的选择。您可能会在专门的库中找到这种代码,而不是在应用程序代码中。

关于c# - 在前提完成之前继续运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73543543/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com