gpt4 book ai didi

c# - 下面的代码是否捕获了 TPL 中原始任务、延续任务和子任务的异常?

转载 作者:太空狗 更新时间:2023-10-29 23:31:08 30 4
gpt4 key购买 nike

我正在使用 TPL 和 async/await 在 webclient 之上为我的应用程序构建异步 API。很少有地方(通常是我需要运行一堆异步任务并最终等待所有这些任务的地方)遵循代码片段。我只是想确保我得到它是正确的,因为即使使用 TPL 和 async/await 编写异步代码相对容易调试/故障排除仍然具有挑战性(在客户现场进行交互式调试和故障排除问题) - 所以想把它做好。

我的目标:能够捕获原始任务、延续任务以及子任务产生的异常,以便我可以处理它(如果需要)。我不希望任何异常(exception)被遗忘。

我使用的基本原则: 1. .net 框架确保异常将附加到任务2. Try/catch block 可以应用于 async/await 以提供同步代码的错觉/可读性(引用:http://channel9.msdn.com/Events/TechDays/Techdays-2014-the-Netherlands/Async-programming-deep-divehttp://blogs.msdn.com/b/ericlippert/archive/2010/11/19/asynchrony-in-c-5-part-seven-exceptions.aspxhttp://msdn.microsoft.com/en-us/library/dd537614.aspx 等)

问题:我希望获得预期目标(我可以从原始任务、继续任务和子任务中捕获异常)的批准,我可以对示例:

例如,是否会出现其中一个组合任务(例如,未包装的代理任务)根本不会被激活(waitforactivation 状态)的情况,因此 waitall 可能只是等待任务开始?我的理解是,这些情况永远不会发生,因为延续任务总是执行,并返回一个已被代理使用 wnwrap 跟踪的任务。只要我在所有层和 API 中遵循类似的模式,该模式就应该捕获链式任务中的所有聚合异常。

注意: 本质上是在寻找建议,例如如果原始任务状态未运行完成,则避免在后续任务中创建虚拟任务,或者使用附加到父级以便我只能等待父级等. 查看所有可能性,以便我可以选择最佳选项,因为此模式严重依赖我的应用程序进行错误处理。

static void SyncAPIMethod(string[] args)
{
try
{
List<Task> composedTasks = new List<Task>();
//the underlying async method follow the same pattern
//either they chain the async tasks or, uses async/await
//wherever possible as its easy to read and write the code
var task = FooAsync();
composedTasks.Add(task);
var taskContinuation = task.ContinueWith(t =>
{
//Intentionally not using TaskContinuationOptions, so that the
//continuation task always runs - so that i can capture exception
//in case something is wrong in the continuation
List<Task> childTasks = new List<Task>();
if (t.Status == TaskStatus.RanToCompletion)
{

for (int i = 1; i <= 5; i++)
{
var childTask = FooAsync();
childTasks.Add(childTask);
}

}
//in case of faulted, it just returns dummy task whose status is set to
//'RanToCompletion'
Task wa = Task.WhenAll(childTasks);
return wa;
});
composedTasks.Add(taskContinuation);
//the unwrapped task should capture the 'aggregated' exception from childtasks
var unwrappedProxyTask = taskContinuation.Unwrap();
composedTasks.Add(unwrappedProxyTask);
//waiting on all tasks, so the exception will be thrown if any of the tasks fail
Task.WaitAll(composedTasks.ToArray());
}
catch (AggregateException ag)
{
foreach(Exception ex in ag.Flatten().InnerExceptions)
{
Console.WriteLine(ex);
//handle it
}
}
}

最佳答案

来自评论:

IMO, this code could could have been much more simpler and elegant with async/await. I don't understand the reason why you stick with ContinueWith and Unwrap, and why you add both the inner and the outer (unwrapped) task to composedTasks.

我的意思是如下所示。我认为它与原始代码的作用相同,但没有 composedTasksContinueWithUnwrap 形式的不必要冗余。如果您使用 async/await,您几乎不需要这些。

static void Main(string[] args)
{
Func<Task> doAsync = async () =>
{
await FooAsync().ConfigureAwait(false);

List<Task> childTasks = new List<Task>();
for (int i = 1; i <= 5; i++)
{
var childTask = FooAsync();
childTasks.Add(childTask);
}

await Task.WhenAll(childTasks);
};

try
{
doAsync().Wait();
}
catch (AggregateException ag)
{
foreach (Exception ex in ag.Flatten().InnerExceptions)
{
Console.WriteLine(ex);
//handle it
}
}
}

static async Task FooAsync()
{
// simulate some CPU-bound work
Thread.Sleep(1000);
// we could have avoided blocking like this:
// await Task.Run(() => Thread.Sleep(1000)).ConfigureAwait(false);

// introduce asynchrony
// FooAsync returns an incomplete Task to the caller here
await Task.Delay(1000).ConfigureAwait(false);
}

已更新以解决评论:

there are some use cases where i continue after 'creating child tasks' to invoke more 'independent' tasks.

基本上,任何异步任务工作流都存在三种常见场景:顺序组合、并行组合或这两者的任意组合(混合组合):

  • 顺序作文:

    await task1;
    await task2;
    await task3;
  • 平行合成:

    await Task.WhenAll(task1, task2, task3);

    // or

    await Task.WhenAny(task1, task2, task3);
  • 混合组成:

    var func4 = new Func<Task>(async () => { await task2; await task3; });
    await Task.WhenAll(task1, func4());

如果上述任何任务执行 CPU 密集型工作,您可以为此使用 Task.Run,例如:

    var task1 = Task.Run(() => CalcPi(numOfPiDigits));

其中 CalcPi 是执行实际计算的同步方法。

关于c# - 下面的代码是否捕获了 TPL 中原始任务、延续任务和子任务的异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24547416/

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