dtb*_*dtb 10 .net c# task-parallel-library
我有一个Task <T>:
Task<A> someTask = ...
Run Code Online (Sandbox Code Playgroud)
此任务可能导致成功,出现故障或取消.
我希望在任务成功时转换结果,如果没有则保留结果.
someTask抛出异常时,这似乎非常困难.
我尝试过的:
Task<B> resultTask = StartMyTask().ContinueWith<B>(
t => Foo(t.Result),
TaskContinuationOptions.OnlyOnRanToCompletion);
Run Code Online (Sandbox Code Playgroud)
resultTask如果出现someTask故障,则会导致取消.我想要它的错.
Task<B> resultTask = StartMyTask().ContinueWith<B>(
t => Foo(t.Result));
Run Code Online (Sandbox Code Playgroud)
这会破坏Visual Studio调试器,因为.Result会引发异常.如果按F5,resultTask按预期出现故障,但它闻起来有气味.
有没有什么办法让resultTask具有相同的结果一样someTask,如果someTask故障?
基本上我要做的是用任务来表达这样的事情:
int F()
{
throw new SomeException();
}
string G(int x)
{
return x.ToString();
}
try
{
string result = G(F());
}
catch (SomeException e)
{
...
}
Run Code Online (Sandbox Code Playgroud)
我怀疑原来的异常会在你的AggregateException内部,AggregateException如果你看到我的意思 - 你只需要打开两次,或者AggregateException.Flatten()在外面打电话AggregateException.
这似乎可行,并且可能类似于@Stephen Cleary建议的“ PipelineTransform” 。
Task<B> resultTask = StartMyTask().ContinueWith<Task<B>>(task =>
{
var tcs = new TaskCompletionSource<B>();
switch (task.Status)
{
case TaskStatus.Canceled:
tcs.SetCanceled();
break;
case TaskStatus.Faulted:
tcs.SetException(task.Exception);
break;
case TaskStatus.RanToCompletion:
tcs.SetResult(Foo(task.Result));
break;
}
return tcs.Task;
}).Unwrap();
Run Code Online (Sandbox Code Playgroud)
任务延续是独立的。它们可用于构建您想要的内容,但它们并不是专门针对该场景而设计的。
要问的第一个问题是:这种关系是否可以被视为父/子关系(例如,Foo将是 的父级StartMyTask)?如果这是有道理的,那么您也许可以利用从子级到父级的状态传播。
如果将Foo“父母”和StartMyTask“孩子”分别对待在设计上不起作用,那么就没有其他选择了。对于您所需要的内容来说,延续性有点低级(请记住,它们只是“在其他任务完成时运行此任务”)。
听起来您可能正在尝试做一些更像“管道”的事情。目前来说,Rx比较适合这种事情。
基于任务的管道还没有真正出现。ParallelExtensionsExtras库有一个基于任务的 Pipeline 类,Async CTP有一个 TPL Dataflow 库,但这两个库目前都尚未开发。(例如,Pipeline 坚持在单独的线程中运行管道的每个阶段,而 Dataflow 没有自动传播异常甚至完成的机制)。
因此,如果您无法使用 Rx,那么我会为任务编写自己的“PipelineTransform”扩展方法,并使用显式 TCS 来正确处理所有三种完成情况。
| 归档时间: |
|
| 查看次数: |
2997 次 |
| 最近记录: |