是否可以(甚至合理)回调System.Timers.Timer
异步方法?类似的东西:
var timer = new System.Timers.Timer
{
Interval = TimeSpan.FromSeconds(30).TotalMilliseconds,
AutoReset = true
};
timer.Elapsed += async (sender, e) => { /* await something */ };
timer.Start();
它编译(显然是一个好的起点),但我不确定我理解后果。在重置计时器之前,计时器await
会回调吗?
答案 0 :(得分:18)
计时器
await
是否会在重置计时器之前进行回调?
没有。 可以等待,因为ElapsedEventHandler
的签名具有void返回类型。
换句话说,您的代码相当于:
var timer = new System.Timers.Timer { ... };
timer.Elapsed += Foo;
timer.Start();
...
private async void Foo()
{
...
}
这对您是否可接受将取决于您的背景。通常,使用异步void方法或匿名函数会使它们更难以测试和重用 - 但是为了事件处理程序而精确地给出了这种能力......你应该考虑如何传播错误。
答案 1 :(得分:3)
问题的标题是关于计时器的,但如果我们将其视为“如何在一段时间后调用异步方法?”然后你可以不用计时器就可以做到。
var task2 = Task.Run(async () => {
while (true)
{
try
{
await MyMethod2();
} catch
{
//super easy error handling
}
await Task.Delay(TimeSpan.FromSeconds(5));
}
});
...
public async Task MyMethod2()
{
//async work here
}
但请注意,这将有不同的时间(定时器将在一定时间间隔调用,上面的代码将每次调用(运行时间+ sleep_time),但即使MyMethod2
花了很长时间它赢了不会被叫两次。话说回来,你可以计算出每隔x分钟运行多长时间。
答案 2 :(得分:-1)
实际上,你可以。
System.Timers.Timer timer = new System.Timers.Timer();
timer.Elapsed += async (x, y) => { await Task.Delay(1); };
答案 3 :(得分:-2)
@tymtam 提出的解决方案不会等到 MyMethod2
结束。
我觉得用这个会更好。
两个异步任务的例子,当两个任务都完成后,等待 5 秒并再次执行这两个任务:
var task2 = Task.Run(async () => {
while (true)
{
try
{
var task1 = MyMethod1();
var task2 = MyMethod2();
List<Task> allTasks = new List<Task> { task1, task2 };
while (allTasks.Count > 0)
{
Task finishedTask = await Task.WhenAny(allTasks);
if (finishedTask == task1)
{
Console.WriteLine("MyMethod1 has ended");
}
else if (finishedTask == task2)
{
Console.WriteLine("MyMethod2 has ended");
}
tareas.Remove(finishedTask);
}
//Here only when finished all task
} catch
{
//super easy error handling
}
//Wait until next cycle
await Task.Delay(TimeSpan.FromSeconds(5));
}
});
...
public async Task MyMethod1()
{
//async work here
}
public async Task MyMethod2()
{
//async work here
}