- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在使用 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-dive、http://blogs.msdn.com/b/ericlippert/archive/2010/11/19/asynchrony-in-c-5-part-seven-exceptions.aspx、http://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.
我的意思是如下所示。我认为它与原始代码的作用相同,但没有 composedTasks
、ContinueWith
和 Unwrap
形式的不必要冗余。如果您使用 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/
我有以下 TPL 数据流,当使用谓词过滤从 TransformBlock 传递到 ActionBlock 的项目时,它永远不会完成。 如果谓词对任何项目返回 false,则数据流挂起。 请有人提供一些
我是 smarty 的新手,所以我不确定这是否会导致我遗漏某些内容,但目前我正在尝试从 css 文件中提取一个类。 到目前为止,我已经设置了 2 个类 mainbackground 和 body,ma
如何强制 TPL 使用固定数量的线程?我知道 MaxDegreeOfParallelism 可用于设置上限,但我希望上限等于下限。这可能吗?怎么办? 因为我知道有人会问 =) 是的,我确定我想这样做,
我正在尝试使用 GXT 3.0 的 XTemplates(类似于 EXT),这里有 2 个具有以下关系的简单 java 对象: class A { String name; public
我刚刚将 Visual Studio 11 Beta 升级到新的 Visual Studio 2012 RC,并且在引用 TPL 数据流时遇到了问题。 首先,我尝试像以前一样通过从框架中添加引用来引用
我需要制作可扩展的流程。该进程主要有 I/O 操作和一些次要的 CPU 操作(主要是反序列化字符串)。该过程在数据库中查询 url 列表,然后从这些 url 中获取数据,将下载的数据反序列化为对象,然
我们有一个 TPL 数据流管道,其中包含以下 block : 变换 block A:Http post call 转换 block B:数据库 IO Transform Block C:一些单位转换数
我有一个 BufferBlock 来发布消息: public class DelimitedFileBlock : ISourceBlock { private ISourceBlock _s
我想在 Windows Azure 上的工作进程中使用 TPL。我希望在队列中添加一个 IJob,它有一个 Run 方法,因此工作线程将包括: 循环 将项目从队列中取出 使用TPL调用IJob.Run
我尝试创 build 计良好的 TPL 数据流管道,以优化系统资源的使用。我的项目是一个 HTML 解析器,它将解析后的值添加到 SQL Server DB 中。我已经有了 future 管道的所有方
我想为特定的内容类型覆盖 page.tpl.php。 我已经尝试过这些东西,对我没有任何作用。 page--article.tpl.php page--node--article.tpl.php pa
我已经完成了这个 POC 并验证了当你创建 4 个线程并在四核机器上运行它们时,所有的核心都会变得忙碌——所以,CLR 已经在不同的核心上有效地调度了线程,那么为什么要使用 TASK 类呢? 我同意
使用Visual Studio Concurrency Visualizer我现在明白为什么切换到 Parallel.For 没有任何好处:只有 9% 的时间机器忙于执行代码,其余的时间为 71% 的
我的代码中有以下使用 TPL 的设置: 我的类中的一个字段:private CancellationTokenSource _cancellationTokenSource; 每次我创建使用特定取消
我有一个 Windows 服务,它在经过漫长的过程后发送电子邮件。每当有表条目并处理它并将其发送出去时,该服务就会继续从数据库表中获取电子邮件数据。 目前它是一个多线程应用程序,我们在生产服务器中将线
刚刚使用 TPL DataFlow 编写了示例生产者消费者模式。我在这里有一些基本问题。 只有在生产者发布所有项目后,消费者才处于事件状态。异步是指生产任务和消费任务都可以并行运行。 给消费者一个 s
我正在使用 TPL,需要有一个长时间运行的 TPL 任务将结果发送到父 UI 线程而不终止。我已经尝试了几种方法,并且已经在谷歌上搜索了很多。有谁知道如何通过 TPL 实现这一点? 最佳答案 您可以传
我有一个以这种方式设置的 TPL 数据流: 下载字节数组 处理数据 将处理后的数据流式传输到另一个位置 此流程运行良好,但偶尔会在下载文件时遇到备份、连接问题等。我想做的是并行下载,但仍确保执行第 3
我有一个应该批量调用并压缩大文件的控制台应用程序,我想使用 DataFlow,除了完成之外一切正常 请考虑以下代码 public static void CompressFiles(string fo
当你生成多个任务时,像这样: for (int i = 0; i ((stateObject) => { tls.Value = (int)stateObject;
我是一名优秀的程序员,十分优秀!