【发布时间】:2015-05-22 03:28:10
【问题描述】:
我正在尝试为任意代码编写一个包装器,该包装器将在给定的超时时间后取消(或至少停止等待)代码。
我有以下测试和实现
[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);
}
和“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();
}
以及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);
}
}
应该发生的情况是测试方法尝试花费 >3000 毫秒并且超时应该发生在 20 毫秒,但这并没有发生。为什么我的代码没有按预期超时?
编辑:
根据要求-decoratedPolicy如下
public async Task ExecuteAsync(Action action, CancellationToken token)
{
token.ThrowIfCancellationRequested();
await Task.Factory.StartNew(action.Invoke, token);
}
【问题讨论】:
-
你在监控
_decoratedPolicy.ExecuteAsync(action, cts.Token);里面的token吗? -
通过监控你到底是什么意思?抱歉 - 这是第一次涉足该领域。这是当前内部“装饰策略” public async Task ExecuteAsync(Action action, CancellationToken token) { await Task.Factory.StartNew(action.Invoke, token); }
-
要解决您的 TODO,只需创建一个 linked cancelation token source
var cts = CancellationTokenSource.CreateLinkedTokenSource(token);。这会创建一个“子源”,可以取消但不会取消传入的令牌,如果传入的令牌被取消,它也会自行取消。编辑:最后一点。链接令牌源是一个好主意,最好将令牌源包装在using语句中,否则您可能会得到一些无法被 GC 处理的长寿命对象 -
不错!我什至没有想过那个 TODO,但谢谢你:)
标签: c# async-await task-parallel-library task