我知道PipeTo
,但有些东西,比如嵌套延续的同步等待,似乎违背了 async & await 方式。
所以,我的第一个问题 [1] 是:这里有什么“魔法”,这样我们就可以连续同步等待嵌套任务,最终它仍然是异步的?
当我们处于异步和等待差异时,如何处理失败?
让我们创建一个简单的示例:
public static class AsyncOperations
{
public async static Task<int> CalculateAnswerAsync()
{
await Task.Delay(1000).ConfigureAwait(false);
throw new InvalidOperationException("Testing!");
//return 42;
}
public async static Task<string> ConvertAsync(int number)
{
await Task.Delay(600).ConfigureAwait(false);
return number + " :)";
}
}
在“常规”、异步和等待方式中:
var answer = await AsyncOperations.CalculateAnswerAsync();
var converted = await AsyncOperations.ConvertAsync(answer);
正如您所期望的那样,异常将从第一次操作中冒出来。
现在,让我们创建一个将处理这些异步操作的参与者。为了争论,假设CalculateAnswerAsync
andConvertAsync
应该一个接一个地用作一个完整的操作(类似于,例如,StreamWriter.WriteLineAsync
如果StreamWriter.FlushAsync
您只想将一行写入流)。
public sealed class AsyncTestActor : ReceiveActor
{
public sealed class Start
{
}
public sealed class OperationResult
{
private readonly string message;
public OperationResult(string message)
{
this.message = message;
}
public string Message
{
get { return message; }
}
}
public AsyncTestActor()
{
Receive<Start>(msg =>
{
AsyncOperations.CalculateAnswerAsync()
.ContinueWith(result =>
{
var number = result.Result;
var conversionTask = AsyncOperations.ConvertAsync(number);
conversionTask.Wait(1500);
return new OperationResult(conversionTask.Result);
})
.PipeTo(Self);
});
Receive<OperationResult>(msg => Console.WriteLine("Got " + msg.Message));
}
}
如果没有例外,我仍然Got 42 :)
没有任何问题,这让我回到了上面的“魔术”点 [1]。此外,示例中提供的AttachedToParent
和ExecuteSynchronously
标志是可选的,还是几乎需要它们才能使一切按预期工作?它们似乎对异常处理没有任何影响......
现在,如果CalculateAnswerAsync
抛出异常,这意味着result.Result
throws AggregateException
,它几乎被吞没了。
如果可能的话,我应该在这里做什么,以使异步操作中的异常像“常规”异常一样使参与者崩溃?