c# - 这是使用 System.Threading.Timer 运行计划的异步/等待方法的正确方法吗?

标签 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
    }
}

最佳答案

I am just unsure about using a async method returning void when that should only be used for event handlers like button clicks

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

通常,我会做一些不同的事情。首先,使用 async over sync anti-pattern ,我会避免。将 Task.Run 移动到调用堆栈中可能的最高位置。然后,如果您只是调用一个单行异步方法,只需返回它而不是等待它,这样您就可以保存异步状态机生成。

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

关于c# - 这是使用 System.Threading.Timer 运行计划的异步/等待方法的正确方法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33133800/

相关文章:

java - 返回空指针的处理程序

c# - 并行内连接

javascript - 回发后 Jquery Fancybox 不工作

python - 单独线程中的 Pandas pd.concat() 显示没有加速

java - 将事件分派(dispatch)线程置于搁置状态,直到 Swing 计时器停止

ios - 如何在异步获取 JSON 数据以填充到 UITableView 时显示 UIActivityIndi​​catorView?

C# 值已声明但从未使用过

c# - 如何在 IIS 上启用读取 C# Excel 文件(在运行 IIS 的机器上本地读取它们工作正常)?

间隔执行后的 JavaScript 回调

javascript - 如何将变量传递给保持不变的异步回调函数?