这是使用System.Threading.Timer运行预定的async / await方法的正确方法吗?

时间:2015-10-14 19:17:52

标签: c# multithreading asynchronous timer async-await

我目前正在开发一个项目,我想在后台执行一些定期更新,我想使用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
    }
}

1 个答案:

答案 0 :(得分:5)

  

我只是不确定使用异步方法返回void,因为它只应用于按钮点击等事件处理程序

好吧,你正在为Timer.Elapsed事件注册一个事件处理程序,所以以这种方式使用它是可以的。

一般来说,我会做一些不同的事情。首先,使用async over sync anti-pattern,我会避免。将Task.Run移动到callstack中可能的最高位置。然后,如果您只是调用单线程异步方法,只需返回它而不是等待它,允许您保存异步状态机生成。

您可以考虑的另一件事是,您可以循环使用Timer,而不是使用Task.DelayTask在内部使用计时器,但会向调用者公开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);