jas*_*son 19
使用System.Threading.Timer.您可以指定定期调用的方法.
例:
Timer timer = new Timer(Callback, null, TimeSpan.Zero, TimeSpan.FromMinutes(5));
public void Callback(object state) {
Console.WriteLine("The current time is {0}", DateTime.Now);
}
Run Code Online (Sandbox Code Playgroud)
您可以使用第二个参数将状态传递给回调.
请注意,您需要以某种方式保持应用程序活动(例如,将其作为服务运行).
至于如何确保它在hh:mm哪里运行mm % 5 == 0,您可以执行以下操作.
DateTime now = DateTime.Now;
int additionalMinutes = 5 - now.Minute % 5;
if(additionalMinutes == 0) {
additionalMinutes = 5;
}
var nearestOnFiveMinutes = new DateTime(
now.Year,
now.Month,
now.Day,
now.Hour,
now.Minute,
0
).AddMinutes(additionalMinutes);
TimeSpan timeToStart = nearestOnFiveMinutes.Subtract(now);
TimeSpan tolerance = TimeSpan.FromSeconds(1);
if (timeToStart < tolerance) {
timeToStart = TimeSpan.Zero;
}
var Timer = new Timer(callback, null, timeToStart, TimeSpan.FromMinutes(5));
Run Code Online (Sandbox Code Playgroud)
需要注意的是,tolerance在这个时候执行代码的情况下,需要now非常接近最近hh:mm有mm % 5 == 0.你可以用小于一秒的值逃脱,但我会把它留给你.
Pet*_*iho 12
六年前发布的答案很有用.但是,恕我直言,有现代化的C#现在是最好使用Task基于API与async和await.另外,我对实现的具体细节略有不同,例如如何管理延迟计算以及如何将当前时间舍入到下一个五分钟间隔.
首先,让我们假设该sendRequest()方法返回void并且没有参数.然后,我们假设基本要求是大约每五分钟运行一次(也就是说它在一小时的五分钟内完全运行并不重要).那么这可以很容易地实现,像这样:
async Task RunPeriodically(Action action, TimeSpan interval, CancellationToken token)
{
while (true)
{
action();
await Task.Delay(interval, token);
}
}
Run Code Online (Sandbox Code Playgroud)
它可以像这样调用:
CancellationTokenSource tokenSource = new CancellationTokenSource();
Task timerTask = RunPeriodically(sendRequest, TimeSpan.FromMinutes(5), tokenSource.Token);
Run Code Online (Sandbox Code Playgroud)
当tokenSource.Cancel()被调用时,循环将被中断TaskCanceledException抛出的await Task.Delay(...)声明.否则,该sendRequest()方法将每五分钟调用一次(在调用该RunPeriodically()方法时立即调用它...如果您希望它在第一次等待,您可以重新排序循环中的语句).
这是最简单的版本.相反,如果您确实希望以五分钟的间隔执行操作,则可以执行类似的操作,但计算下一次运行时间并延迟一段适当的时间.例如:
// private field somewhere appropriate; it would probably be best to put
// this logic into a reusable class.
DateTime _nextRunTime;
async Task RunPeriodically(Action action,
DateTime startTime, TimeSpan interval, CancellationToken token)
{
_nextRunTime = startTime;
while (true)
{
TimeSpan delay = _nextRunTime - DateTime.UtcNow;
if (delay > TimeSpan.Zero)
{
await Task.Delay(delay, token);
}
action();
_nextRunTime += interval;
}
}
Run Code Online (Sandbox Code Playgroud)
这样称呼:
CancellationTokenSource tokenSource = new CancellationTokenSource();
DateTime startTime = RoundCurrentToNextFiveMinutes();
Task timerTask = RunPeriodically(sendRequest,
startTime, TimeSpan.FromMinutes(5), tokenSource.Token);
Run Code Online (Sandbox Code Playgroud)
辅助方法RoundCurrentToNextFiveMinutes()如下所示:
DateTime RoundCurrentToNextFiveMinutes()
{
DateTime now = DateTime.UtcNow,
result = new DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0);
return result.AddMinutes(((now.Minute / 5) + 1) * 5);
}
Run Code Online (Sandbox Code Playgroud)
在任一示例中,timerTask对象都可用于监视循环的状态.在大多数情况下,可能不需要它.但是如果你想能够,例如,await直到代码的其他部分取消循环,这个对象就是你要使用的.
请注意,该Task.Delay()方法在其实现中确实使用了计时器.上述内容不是为了避免使用计时器,而是为了使用现代C#async/ await功能显示原始目标的实现.此版本将与已使用async/的其他代码更清晰地进行网格划分await.
使用System.Threading.Timer:
var timer = new Timer(TimerTick, null, TimeSpan.Zero, new TimeSpan(0, 0, 0, 1));
int lastMinute = 1;
void TimerTick(object state)
{
var minute = DateTime.Now.Minutes;
if (minute != lastMinute && minute % 5 == 0)
{
lastMinute = minute;
//do stuff
}
}
Run Code Online (Sandbox Code Playgroud)
这可能看起来有点笨拙和低效,因为它必须每秒调用一次,但实际上每秒执行一次检查的CPU周期数实际上几乎可以忽略不计.
(对不起,如果代码不是100%正确;我现在没有IDE.
你可以创建一个包含这样的循环的线程
void Runner(){
while(1){
Thread t = new thread( target_method );
t.start();
sleep(5 * 60 * 1000);
}
}
Run Code Online (Sandbox Code Playgroud)
这有点快,又脏,但要做的工作:)