Pau*_*ney 2 c# task task-parallel-library async-await
我正在尝试为任意代码编写一个包装器,在给定的超时期限后取消(或至少停止等待)代码。
我有以下测试和实现
[Test]
public void Policy_TimeoutExpires_DoStuff_TaskShouldNotContinue()
{
var cts = new CancellationTokenSource();
var fakeService = new Mock<IFakeService>();
IExecutionPolicy policy = new TimeoutPolicy(new ExecutionTimeout(20), new DefaultExecutionPolicy());
Assert.Throws<TimeoutException>(async () => await policy.ExecuteAsync(() => DoStuff(3000, fakeService.Object), cts.Token));
fakeService.Verify(f=>f.DoStuff(),Times.Never);
}
Run Code Online (Sandbox Code Playgroud)
和“DoStuff”方法
private static async Task DoStuff(int sleepTime, IFakeService fakeService)
{
await Task.Delay(sleepTime).ConfigureAwait(false);
var result = await Task.FromResult("bob");
var test = result + "test";
fakeService.DoStuff();
}
Run Code Online (Sandbox Code Playgroud)
以及 IExecutionPolicy.ExecuteAsync 的实现
public async Task ExecuteAsync(Action action, CancellationToken token)
{
var cts = new CancellationTokenSource();//TODO: resolve ignoring the token we were given!
var task = _decoratedPolicy.ExecuteAsync(action, cts.Token);
cts.CancelAfter(_timeout);
try
{
await task.ConfigureAwait(false);
}
catch(OperationCanceledException err)
{
throw new TimeoutException("The task did not complete within the TimeoutExecutionPolicy window of" + _timeout + "ms", err);
}
}
Run Code Online (Sandbox Code Playgroud)
什么应该发生的是,测试方法,试图采取> 3000ms和超时应该发生在20毫秒,但这没有发生。为什么我的代码没有按预期超时?
编辑:
根据要求 - 装饰政策如下
public async Task ExecuteAsync(Action action, CancellationToken token)
{
token.ThrowIfCancellationRequested();
await Task.Factory.StartNew(action.Invoke, token);
}
Run Code Online (Sandbox Code Playgroud)
如果我理解正确,您正在尝试为不支持超时/取消的方法支持超时。
通常,这是通过启动具有所需超时值的计时器来完成的。如果计时器首先触发,那么您可以抛出异常。使用 TPL,您可以使用Task.Delay(_timeout)而不是计时器。
public async Task ExecuteAsync(Action action, CancellationToken token)
{
var task = _decoratedPolicy.ExecuteAsync(action, token);
var completed = await Task.WhenAny(task, Task.Delay(_timeout));
if (completed != task)
{
throw new TimeoutException("The task did not complete within the TimeoutExecutionPolicy window of" + _timeout + "ms");
}
}
Run Code Online (Sandbox Code Playgroud)
注意:这不会停止_decoratedPolicy.ExecuteAsync方法的执行,而是忽略它。
如果您的方法确实支持取消(但不及时),那么最好在超时后取消任务。您可以通过创建链接令牌来实现。
public async Task ExecuteAsync(Action action, CancellationToken token)
{
using(var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(token))
{
var task = _decoratedPolicy.ExecuteAsync(action, linkedTokenSource.Token);
var completed = await Task.WhenAny(task, Task.Delay(_timeout));
if (completed != task)
{
linkedTokenSource.Cancel();//Try to cancel the method
throw new TimeoutException("The task did not complete within the TimeoutExecutionPolicy window of" + _timeout + "ms");
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2006 次 |
| 最近记录: |