将异步回调传递给Timer构造函数
本文关键字:Timer 构造函数 异步 回调 | 更新日期: 2023-09-27 18:02:13
我有一个异步回调,它被传递给Timer(从System.Threading)构造函数:
private async Task HandleTimerCallback(object state)
{
if (timer == null) return;
if (asynTaskCallback != null)
{
await HandleAsyncTaskTimerCallback(state);
}
else
{
HandleSyncTimerCallback(state);
}
}
And Timer:
timer = new Timer(async o => await HandleTimerCallback(o), state, CommonConstants.InfiniteTimespan,
CommonConstants.InfiniteTimespan);
在lambda中是否有办法省略o
参数?因为对于非异步,我可以将handler
作为委托传递
timer = new Timer(HandleTimerCallback, state, CommonConstants.InfiniteTimespan,
CommonConstants.InfiniteTimespan);
是否有任何方法可以省略lambda中的0参数?
当然,只需将事件处理程序方法定义为async void
:
private async void HandleTimerCallback(object state)
您可以使用包装器方法,就像David Fowler在这里推荐的那样:
public class Pinger
{
private readonly Timer _timer;
private readonly HttpClient _client;
public Pinger(HttpClient client)
{
_client = client;
_timer = new Timer(Heartbeat, null, 1000, 1000);
}
public void Heartbeat(object state)
{
// Discard the result
_ = DoAsyncPing();
}
private async Task DoAsyncPing()
{
await _client.GetAsync("http://mybackend/api/ping");
}
}
我只是想提一下。net 6引入了一个名为PeriodicTimer
的新定时器类,它是异步优先的,并且完全避免了回调。
的用法一开始看起来有点奇怪(因为它是一个无限循环),但由于它是异步的,它不会阻塞其他线程的执行:
public async Task DoStuffPeriodically()
{
var timer = new PeriodicTimer(TimeSpan.FromSeconds(10));
while (await timer.WaitForNextTickAsync())
{
//do stuff
}
}
它完全避免了回调,使用更简单的代码,是后台服务的完美候选。
你会得到一个"永不结束的任务"
要启动任务,只需调用_ = DoStuffPeriodically()
,例如使用丢弃操作符(但要在方法中添加try-catch
,以便后台任务不会崩溃)或通过Task.Run
启动该任务
Nick Chapsas有一个很好的视频解释使用:https://www.youtube.com/watch?v=J4JL4zR_l-0(包括如何使用CancellationToken
中止定时器)。
我使用了上面建议的Vlad包装器,但随后使用了Task。等待异步进程完成:
private void ProcessWork(object state)
{
Task.WaitAll(ProcessScheduledWorkAsync());
}
protected async Task ProcessWorkAsync()
{
}
如果您不想使用包装器类,您可以在TimerCallback函数中这样做:
private void TimerFunction(object state)
{
_ = Task.Run(async () =>
{
await this.SomeFunctionAsync().ConfigureAwait(false);
});
}