每小时执行一次方法
本文关键字:一次 方法 执行 每小时 | 更新日期: 2023-09-27 18:34:54
我想每小时执行一个方法。我写了一些代码,但这还不足以满足我的目的。下面的代码每 60 分钟工作一次。
public void Start()
{
System.Threading.Timer timerTemaUserBilgileri = new System.Threading.Timer(new System.Threading.TimerCallback(RunTakip), null, tmrTemaUserBilgileri, 0);
}
public void RunTakip(object temauserID)
{
try
{
string objID = "6143566557387";
EssentialMethod(objID);
TimeSpan span = DateTime.Now.Subtract(lastRunTime);
if (span.Minutes > 60)
{
tmrTemaUserBilgileri = 1 * 1000;
timerTemaUserBilgileri.Change(tmrTemaUserBilgileri, 0);
}
else
{
tmrTemaUserBilgileri = (60 - span.Minutes) * 60 * 1000;
timerTemaUserBilgileri.Change(tmrTemaUserBilgileri, 0);
}
watch.Stop();
var elapsedMs = watch.ElapsedMilliseconds;
}
catch (Exception ex)
{
timerTemaUserBilgileri.Change(30 * 60 * 1000, 0);
Utils.LogYaz(ex.Message.ToString());
}
}
public void EssentialMethod(objec obj)
{
//some code
lastRunTime = DateTime.Now;
//send lastruntime to sql
}
如果您希望每 60 分钟执行一次代码:
aTimer = new System.Timers.Timer(60 * 60 * 1000); //one hour in milliseconds
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Start();
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
//Do the stuff you want to be done every hour;
}
如果您希望每小时执行一次代码(即 1:00、2:00、3:00(,您可以创建一个间隔较短的计时器(假设一秒钟,取决于您需要的精度(,并在该计时器事件中检查是否已经过了一个小时
aTimer = new System.Timers.Timer(1000); //One second, (use less to add precision, use more to consume less processor time
int lastHour = DateTime.Now.Hour;
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Start();
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
if(lastHour < DateTime.Now.Hour || (lastHour == 23 && DateTime.Now.Hour == 0))
{
lastHour = DateTime.Now.Hour;
YourImportantMethod(); // Call The method with your important staff..
}
}
我同意Señor Salt的观点,即chron工作应该是首选。 但是,OP 要求每小时从 c# 中获取一小时。 为此,我将第一个定时事件设置为在整点触发:
int MilliSecondsLeftTilTheHour()
{
int interval;
int minutesRemaining = 59 - DateTime.Now.Minute;
int secondsRemaining = 59 - DateTime.Now.Second;
interval = ((minutesRemaining * 60) + secondsRemaining) * 1000;
// If we happen to be exactly on the hour...
if (interval == 0)
{
interval = 60 * 60 * 1000;
}
return interval;
}
Timer timer = new Timer();
timer.Tick += timer_Tick;
timer.Enabled = true;
timer.Interval = MilliSecondsLeftTilTheHour();
现在的问题是,如果上述计时器。间隔恰好是 45 分 32 秒,然后计时器将每 45:32 继续触发一次,而不仅仅是第一次。 因此,在timer_Tick方法中,您必须重新调整计时器。间隔为一小时。
void timer_Tick(object sender, EventArgs e)
{
// The Interval could be hard wired here to 60 * 60 * 1000 but on clock
// resets and if the job ever goes longer than an hour, why not
// recalculate once an hour to get back on track.
timer.Interval = MilliSecondsLeftTilTheHour();
DoYourThing();
}
只是一个基于/Anarion 解决方案的小评论,我无法放入评论中。
您可以创建一个间隔较短的计时器(假设一秒钟,具体取决于您需要的精度(
你根本不需要它来精确地进行,你在想"我如何检查这个小时是我想发射的小时"。你也可以想"我如何检查下一个小时是我想触发的小时"——一旦你这样想,你就会意识到你根本不需要任何精度,只需每小时打勾一次,并为下一个小时设置一个线程。如果你每小时打勾一次,你知道你会在下一个小时之前的某个时间点。
Dim dueTime As New DateTime(Date.Today.Year, Date.Today.Month, Date.Today.Day, DateTime.Now.Hour + 1, 0, 0)
Dim timeRemaining As TimeSpan = dueTime.Subtract(DateTime.Now)
t = New System.Threading.Timer(New System.Threading.TimerCallback(AddressOf Method), Nothing, CType(timeRemaining.TotalMilliseconds, Integer), System.Threading.Timeout.Infinite)
更简单的东西怎么样? 使用一分钟计时器检查小时:
public partial class Form1 : Form
{
int hour;
public Form1()
{
InitializeComponent();
if(RunOnStartUp)
hour = -1;
else
hour = DateTime.Now.Hour;
}
private void timer1_Tick(object sender, EventArgs e)
{
// once per minute:
if(DateTime.Now.Hour != hour)
{
hour = DateTime.Now.Hour;
DailyTask();
}
}
private DailyTask()
{
// do something
}
}
使用服务器上的 Cron 作业以指定的时间间隔调用函数
这是一个链接http://www.thesitewizard.com/general/set-cron-job.shtml
尝试下面的代码怎么样,循环被确定为节省您的资源,并且它每 EXACT 小时运行一次,即分钟和秒(几乎毫秒等于零:
using System;
using System.Threading.Tasks;
namespace COREserver{
public static partial class COREtasks{ // partial to be able to split the same class in multiple files
public static async void RunHourlyTasks(params Action[] tasks)
{
DateTime runHour = DateTime.Now.AddHours(1.0);
TimeSpan ts = new TimeSpan(runHour.Hour, 0, 0);
runHour = runHour.Date + ts;
Console.WriteLine("next run will be at: {0} and current hour is: {1}", runHour, DateTime.Now);
while (true)
{
TimeSpan duration = runHour.Subtract(DateTime.Now);
if(duration.TotalMilliseconds <= 0.0)
{
Parallel.Invoke(tasks);
Console.WriteLine("It is the run time as shown before to be: {0} confirmed with system time, that is: {1}", runHour, DateTime.Now);
runHour = DateTime.Now.AddHours(1.0);
Console.WriteLine("next run will be at: {0} and current hour is: {1}", runHour, DateTime.Now);
continue;
}
int delay = (int)(duration.TotalMilliseconds / 2);
await Task.Delay(30000); // 30 seconds
}
}
}
}
为什么每个人都试图用计时器来处理这个问题?
你在做两件事...等到整点的顶部,然后在整点每小时运行一次计时器。
我有一个Windows服务,我需要同样的解决方案。 我以一种非常冗长的方式编写了我的代码,以便任何人都可以轻松理解。 我知道有很多捷径可以实施,但我把它留给你。
private readonly Timer _timer;
/// starts timer
internal void Start()
{
int waitTime = calculateSleepTime();
System.Threading.Thread.Sleep(waitTime);
object t = new object();
EventArgs e = new EventArgs();
CheckEvents(t, e);
_timer.Start();
}
/// runs business logic everytime timer goes off
internal void CheckEvents(object sender, EventArgs e)
{
// do your logic here
}
/// Calculates how long to wait until the top of the hour
private int calculateSleepTime()
{
DateTime now = DateTime.Now;
int minutes = now.Minute * 60 * 1000;
int seconds = now.Second * 1000;
int substrahend = now.Millisecond + seconds + minutes;
int minuend = 60 * 60 * 1000;
return minuend - substrahend;
}
这是一个简单、稳定(自同步(的解决方案:
while(true) {
DoStuff();
var now = DateTime.UtcNow;
var previousTrigger = new DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0, now.Kind);
var nextTrigger = previousTrigger + TimeSpan.FromHours(1);
Thread.Sleep(nextTrigger - now);
}
请注意,如果执行迭代的时间超过一小时DoStuff()
则可以跳过。
下面是一个简化的示例:当它初始化时,获取它需要执行的下一个时间点,然后从中减去现在。这为您提供了距离第一个事件的时间。将其用作第一个事件的到期时间。现在,每个事件都将以您指定的间隔触发,在本例中为 Hour。
internal class Program
{
static Timer? _Timer;
static void Main(string[] args)
{
DateTimeOffset now = DateTimeOffset.UtcNow;
DateTimeOffset dueHour = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, 0, 0, TimeSpan.Zero).AddHours(1);
_Timer = new Timer(DoTask, null, dueHour.Subtract(DateTimeOffset.UtcNow), TimeSpan.FromHours(1));
Console.ReadKey();
}
static private void DoTask(object? state)
{
Console.WriteLine(DateTimeOffset.UtcNow.ToString());
}
}