异步任务的顺序处理 [英] Sequential processing of asynchronous tasks
问题描述
假设以下同步code:
Assume the following synchronous code:
try
{
Foo();
Bar();
Fubar();
Console.WriteLine("All done");
}
catch(Exception e) // For illustration purposes only. Catch specific exceptions!
{
Console.WriteLine(e);
}
现在假设所有这些方法都有一个异步对口,我不得不使用那些由于某种原因,所以简单地把整个事情在一个新的任务是不是一种选择。
我将如何实现相同的行为?
我的意思与同是:
Now assume all these methods have an Async counterpart and I have to use those for some reason, so simply wrapping the whole thing in a new task is not an option.
How would I achieve the same behavior?
What I mean with "same" is:
- 执行一个异常处理程序,如果被抛出。
- 停止执行下面的方法,如果有异常被抛出。
我唯一能拿出来说的的可怕的
The only thing I was able to come up with is horrible:
var fooTask = FooAsync();
fooTask.ContinueWith(t => HandleError(t.Exception),
TaskContinuationOptions.OnlyOnFaulted);
fooTask.ContinueWith(
t =>
{
var barTask = BarAsync();
barTask.ContinueWith(t => HandleError(t.Exception),
TaskContinuationOptions.OnlyOnFaulted);
barTask.ContinueWith(
t =>
{
var fubarTask = FubarAsync();
fubarTask.ContinueWith(t => HandleError(t.Exception),
TaskContinuationOptions.OnlyOnFaulted);
fubarTask.ContinueWith(
t => Console.WriteLine("All done"),
TaskContinuationOptions.OnlyOnRanToCompletion);
},
TaskContinuationOptions.OnlyOnRanToCompletion);
},
TaskContinuationOptions.OnlyOnRanToCompletion);
请注意:
- 我需要一个解决方案,使用.NET 4的作品,所以
异步/计谋
是出了问题。但是,如果将与工作异步/计谋
随意展示如何。 - 在我不需要使用第三方物流。如果是与第三方物流是不可能的另一种方法是好的,可能与无功扩展?
- I need a solution that works with .NET 4, so
async/await
is out of the question. However, if it would work withasync/await
feel free to show how. - I don't need to use the TPL. If it is impossible with the TPL another approach would be OK, maybe with Reactive Extensions?
推荐答案
下面是如何将与工作异步
:
try
{
await FooAsync();
await BarAsync();
await FubarAsync();
Console.WriteLine("All done");
}
catch(Exception e) // For illustration purposes only. Catch specific exceptions!
{
Console.WriteLine(e);
}
如果您安装了($ P $租赁前) Microsoft.Bcl.Async包这将工作在.NET 4.0一>
This would work on .NET 4.0 if you installed the (prerelease) Microsoft.Bcl.Async package.
既然你被困在VS2010,您可以使用斯蒂芬变体Toub的然后
:
Since you're stuck on VS2010, you can use a variant of Stephen Toub's Then
:
public static Task Then(this Task first, Func<Task> next)
{
var tcs = new TaskCompletionSource<object>();
first.ContinueWith(_ =>
{
if (first.IsFaulted) tcs.TrySetException(first.Exception.InnerExceptions);
else if (first.IsCanceled) tcs.TrySetCanceled();
else
{
try
{
next().ContinueWith(__ =>
{
if (t.IsFaulted) tcs.TrySetException(t.Exception.InnerExceptions);
else if (t.IsCanceled) tcs.TrySetCanceled();
else tcs.TrySetResult(null);
}, TaskContinuationOptions.ExecuteSynchronously);
}
catch (Exception exc) { tcs.TrySetException(exc); }
}
}, TaskContinuationOptions.ExecuteSynchronously);
return tcs.Task;
}
您可以使用它作为这样的:
You can use it as such:
var task = FooAsync().Then(() => BarAsync()).Then(() => FubarAsync());
task.ContinueWith(t =>
{
if (t.IsFaulted || t.IsCanceled)
{
var e = t.Exception.InnerException;
// exception handling
}
else
{
Console.WriteLine("All done");
}
}, TaskContinuationOptions.ExcecuteSynchronously);
使用接收,它看起来像这样(假设你不已经暴露的IObservable和其中的
):异步
方法;单元&gt;
Using Rx, it would look like this (assuming you don't have the async
methods already exposed as IObservable<Unit>
):
FooAsync().ToObservable()
.SelectMany(_ => BarAsync().ToObservable())
.SelectMany(_ => FubarAsync().ToObservable())
.Subscribe(_ => { Console.WriteLine("All done"); },
e => { Console.WriteLine(e); });
我想。我不是一个接收主,以任何方式。 :)
I think. I'm not an Rx master, by any means. :)
这篇关于异步任务的顺序处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!