Kei*_*ows 1 .net c# async-await
我正在尝试测试一个使用async/await处理事务并使用await/async轮询功能的小应用程序.
我的测试设置:
[TestMethod]
public void TestProcessTimerOnly()
{
// this initializes and kicks off the polling
var tp = new TransactionProcessor();
try
{
Thread.Sleep(5000);
tp.CancelProcessing();
}
catch (Exception ex)
{
LogErrors(ref tp, ex);
}
finally
{
DisplayLog(tp);
}
}
[TestMethod]
public void TestProcessTimerOnlyForcedCancellation()
{
// this initializes and kicks off the polling
var tp = new TransactionProcessor(1);
try
{
Thread.Sleep(5000);
tp.CancelProcessing();
}
catch (Exception ex)
{
LogErrors(ref tp, ex);
}
finally
{
DisplayLog(tp);
}
}
Run Code Online (Sandbox Code Playgroud)
我的代码(全部在一个类中):
// Constructor
public TransactionProcessor(int? debugForcedCancellationDelay = null)
{
// >>>>>>>> Setup Cancellation <<<<<<<<
if(debugForcedCancellationDelay.IsEmpty() || debugForcedCancellationDelay.IsZeroOrLess())
_cancellationToken = new CancellationTokenSource();
else
_cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(debugForcedCancellationDelay.Value));
// >>>>>>>> End <<<<<<<<
// was:
// RepeatActionEvery(() => TestingLog.Add("Repeat Action Every 1 Second"), TimeSpan.FromSeconds(1), _cancellationToken.Token).Wait();
// corrected:
// _processTask is defined as a global field of type Task...
_processTask = RepeatActionEvery(() => TestingLog.Add("Repeat Action Every 1 Second"), TimeSpan.FromSeconds(1), _cancellationToken.Token); //.Wait();
}
// was:
//public void CancelProcessing()
// corrected:
public async Task CancelProcessing()
{
_cancellationToken.Cancel();
await _processTask;
}
public static async Task RepeatActionEvery(Action action, TimeSpan interval, CancellationToken cancellationToken)
{
while (true)
{
action();
var task = Task.Delay(interval, cancellationToken);
try { await task; }
catch (TaskCanceledException) { return; }
}
}
Run Code Online (Sandbox Code Playgroud)
当我运行TestProcessTimerOnly()测试时,它会坐在那里直到我最终取消测试装备.
当我运行TestProcessTimerOnlyForcedCancellation()测试时,它的行为符合预期.
所以问题归结为:我是否正确使用_cancellationToken变量?在一个实例中,我使用超时参数初始化它.在另一个例子中,我初始化它没有参数.我在这做错了什么?
你正在使用"同步异步",这是非常气馁的.
您将获得一项任务,RepeatActionEvery只有在取消令牌被取消时才会结束.但是你正在等待该任务的同步(阻塞),这意味着你永远不会离开构造函数并到达取消令牌(tp.CancelProcessing();)的行.
当然,当你创建CancellationTokenSource一个超时时,它最终将取消自己,而不必调用它,所以任务将结束,等待它的线程将可以自由地完成构造函数和调用tp.CancelProcessing();
您应该做的事情(IIUC)是存储事务任务而不等待它,并且仅在您取消(或完成)事务时等待:
public TransactionProcessor(int? debugForcedCancellationDelay = null)
{
// ...
Task = RepeatActionEvery(
() => TestingLog.Add("Repeat Action Every 1 Second"),
TimeSpan.FromSeconds(1),
_cancellationToken.Token);
}
public async Task CancelProcessingAsync()
{
_cancellationToken.Cancel();
await Task;
}
Run Code Online (Sandbox Code Playgroud)