翻译自:https://github.com/App-vNext/Polly/wiki/Avoid-compiler-gotchas-mixing-sync-and-async-execution/_edit
点此跳转到系列目录
Asynchronous action execution
有关可用语法和策略的概述,请首先阅读自述文件:https://github.com/App-vNext/Polly#asynchronous-support。这篇文章详细描述了策略的异步操作.
Polly完全支持异步执行,使用异步方法:
RetryAsync
WaitAndRetryAsync
CircuitBreakerAsync
- (etc)
ExecuteAsync
ExecuteAndCaptureAsync
取代他们对应的同步语法 Retry
, WaitAndRetry
等.
策略实例是定义为同步或异步执行,但不能同时执行同步和异步。 您必须对同步定义的策略(如Retry
)使用同步执行重载(如Execute
); 对异步义的策略(如 RetryAsync
)使用异步执行重载(如ExecuteAsync
);
Async / await
在异步执行中, 所有的委托都是async
,执行都需要 await
.
SynchronizationContext
作为提供异步API的库的推荐,默认情况下,异步延续(当方法从’ await '恢复时)不会在捕获的同步上下文上运行。
如果你需要整个.ExecuteAsync(…)
调用在捕获的同步上下文中继续执行,请使用带bool continueOnCapturedContext
的重载,并将其设置为true
。
Cancellation support
使用带有CancellationToken
参数的 .ExecuteAsync(…)
(或类似的)方法表示此异步任务可以取消。取消可能发生在如下情况:
- 在委托尚未执行之前: 与
Task.Run(…)
和其他地方的基类库实现一样,如果在执行开始之前取消了取消令牌,则委托根本不会执行。 - 在委托执行期间: 相关的
.ExecuteAsync(…)
重载所采取的操作委托具有CancellationToken
输入参数。CancellationToken
传递给.ExecuteAsync(…)
调用,并作为CancellationToken
输入参数传递给被执行的委托,以支持在委托执行期间取消。 - 在任何等待操作期间执行策略: 例如,重试之间的等待;等待舱壁执行槽。
所有取消都会照常抛出OperationCanceledException
。
Use async policies consistently for async execution
如果你错误地将一个同步策略与一个异步执行重载结合,如下所示(或反之亦然):
// Synchronous policy
var policy = Policy
.Handle<Exception>()
.Retry(3); // sync policy
// Asynchronous execute overload
var something = await policy.ExecuteAsync(async () => await DoSomethingAsync()); // async execute overload
那么Polly(直到v6)将抛出’ InvalidOperationException '。(从Polly v7开始,上面的示例将无法编译。)
使用Polly就像使用.Net中的其他异步代码一样,要注意同步和异步代码的混合.
避免混合执行同步和异步的编译器陷阱
(Avoid compiler gotchas mixing sync and async execution)
避免如下形式代码:
// 同步策略
var policy = Policy
.Handle<Exception>()
.Retry(3);
// NB 不好的代码: 同步执行了异步的委托!
var something = await policy.Execute(async () => await DoSomethingAsync());
编译器将允许上述代码进行编译,因为async
严格来说不是方法签名的一部分; 代码解析编译一个恰好返回Task<T>
的委托。Polly还不能因为任何同步/异步不匹配而抛出或编译失败,因为策略(Retry
)和执行重载(Execute
)都匹配为同步。
注意 然而,Polly策略不会用这段代码来控制’ DoSomethingAsync() '的整个异步执行生命周期!
为什么它不工作?
当执行遇到第一个await语句时,所有.NET async
方法都会同步返回一个表示正在执行的Task
。 当一个异步委托,例如async () => await DoSomethingAsync()
通过同步policy.Execute(...)
运行时,策略只控制同步执行直到第一个await
语句返回该’ Task '。
异步任务继续执行,并可能抛出错误,将错误放入返回的Task
中。 然而,代码随后在策略执行外部等待任务(await policy.Execute(...)
),因为同步策略执行已经成功完成同步返回Task
。 因为上面的代码会在策略执行之外等待有错误的“任务”,所以异常会在没有策略控制的情况下被重新抛出。
翻译自:https://github.com/App-vNext/Polly/wiki/Avoid-compiler-gotchas-mixing-sync-and-async-execution/_edit
点此跳转到系列目录