【发布时间】:2019-06-03 09:44:39
【问题描述】:
我有一个方法RestartAsync,它启动了一个方法DoSomethingAsync。当再次调用RestartAsync 时,它应该取消DoSomethingAsync 并等待它完成(DoSomethingAsync 不能同步取消,并且不应在前一个任务仍在进行时调用它)。
我的第一个方法是这样的:
public async Task RestartTest()
{
Task[] allTasks = { RestartAsync(), RestartAsync(), RestartAsync() } ;
await Task.WhenAll(allTasks);
}
private async Task RestartAsync()
{
_cts.Cancel();
_cts = new CancellationTokenSource();
await _somethingIsRunningTask;
_somethingIsRunningTask = DoSomethingAsync(_cts.Token);
await _somethingIsRunningTask;
}
private static int _numberOfStarts;
private async Task DoSomethingAsync(CancellationToken cancellationToken)
{
_numberOfStarts++;
int numberOfStarts = _numberOfStarts;
try
{
Console.WriteLine(numberOfStarts + " Start to do something...");
await Task.Delay(TimeSpan.FromSeconds(1)); // This operation can not be cancelled.
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
Console.WriteLine(numberOfStarts + " Finished to do something...");
}
catch (OperationCanceledException)
{
Console.WriteLine(numberOfStarts + " Cancelled to do something...");
}
}
调用 RestartAsync 三次时的实际输出如下所示(注意第二次运行取消并等待第一次,但同时第三次运行也在等待第一次,而不是取消并等待第二次):
1 Start to do something...
1 Cancelled to do something...
2 Start to do something...
3 Start to do something...
2 Finished to do something...
3 Finished to do something...
但我想要实现的是这个输出:
1 Start to do something...
1 Cancelled to do something...
2 Start to do something...
2 Cancelled to do something...
3 Start to do something...
3 Finished to do something...
我目前的解决方案如下:
private async Task RestartAsync()
{
if (_isRestarting)
{
return;
}
_cts.Cancel();
_cts = new CancellationTokenSource();
_isRestarting = true;
await _somethingIsRunningTask;
_isRestarting = false;
_somethingIsRunningTask = DoSomethingAsync(_cts.Token);
await _somethingIsRunningTask;
}
然后我得到这个输出:
1 Start to do something...
1 Cancelled to do something...
2 Start to do something...
2 Finished to do something...
现在至少 DoSomethingAsync 仍在进行中时没有启动(请注意,忽略第三次运行,这并不重要,否则它应该取消第二次运行)。
但是这个解决方案感觉不好,我必须在任何我想要这种行为的地方重复这种丑陋的模式。 这种重启机制有什么好的模式或框架吗?
【问题讨论】:
标签: c# .net concurrency async-await task-parallel-library