我目前正在开发一个项目,我想在后台执行一些定期更新,我想使用System.Threading.Timer为此目的使用async / await。我找不到关于这个特定主题的任何文章。
以下代码段有效。我只是不确定使用异步方法返回void,因为它只应用于按钮点击等事件处理程序。在下面的代码中是否有任何“违反”最佳做法的行为?
public class ScheduledCache
{
private CancellationTokenSource _cancelSource = new CancellationTokenSource();
private Request _request = new Request();
private Timer _timer;
public void Start()
{
_cancelSource = new CancellationTokenSource();
_timer = new Timer(UpdateAsync, null, 2000, Timeout.Infinite);
}
public void Stop()
{
_cancelSource.Cancel();
}
public async void UpdateAsync(object state)
{
try
{
await Task.WhenAll(UpdateSomethingAsync(_cancelSource.Token), UpdateSomethingElseAsync(_cancelSource.Token));
}
catch (OperationCanceledException)
{
// Handle cancellation
}
catch (Exception exception)
{
// Handle exception
}
finally
{
if (_cancelSource.IsCancellationRequested)
_timer = new Timer(UpdateAsync, null, 2000, Timeout.Infinite);
else
_timer = new Timer(UpdateAsync, null, Timeout.Infinite, Timeout.Infinite);
}
}
private async Task UpdateSomethingAsync(CancellationToken cancellationToken)
{
await Task.Run(new Action(_request.UpdateSomething));
}
private async Task UpdateSomethingElseAsync(CancellationToken cancellationToken)
{
await Task.Run(new Action(_request.UpdateSomethingElse));
}
}
public class Request
{
public void UpdateSomething()
{
// Do some updates here
}
public void UpdateSomethingElse()
{
// Do some other updates here
}
}
答案 0 :(得分:5)
我只是不确定使用异步方法返回void,因为它只应用于按钮点击等事件处理程序
好吧,你正在为Timer.Elapsed
事件注册一个事件处理程序,所以以这种方式使用它是可以的。
一般来说,我会做一些不同的事情。首先,使用async over sync anti-pattern,我会避免。将Task.Run
移动到callstack中可能的最高位置。然后,如果您只是调用单线程异步方法,只需返回它而不是等待它,允许您保存异步状态机生成。
您可以考虑的另一件事是,您可以循环使用Timer
,而不是使用Task.Delay
,Task
在内部使用计时器,但会向调用者公开public async Task StartAsync()
{
_cancelSource = new CancellationTokenSource();
await UpdateAsync(_cancelSource.Token);
}
public async Task UpdateAsync(CancellationToken cancellationToken)
{
try
{
var updateSomething = Task.Run(() => _request.UpdateSomething()));
var updateSomethingElse = Task.Run(() => _request.UpdateSomethingElse());
await Task.WhenAll(updateSomething, updateSomethingElse);
}
catch (OperationCanceledException)
{
// Handle cancellation
}
catch (Exception exception)
{
// Handle exception
}
finally
{
if (_cancelSource.IsCancellationRequested)
await Task.Delay(2000);
}
}
。
大致可以这样:
AfxGetMainWnd()->PostMessage(WM_COMMAND, ID_FILE_OPEN, 0);