简体   繁体   English

每小时执行一次方法

[英]Executing method every hour on the hour

I want to execute a method every hour on the hour.我想每小时执行一个方法。 I wrote some code,but it is not enough for my aim.我写了一些代码,但这对我的目标来说还不够。 Below code is working every 60 minutes.下面的代码每 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 
}

If you want your code to be executed every 60 minutes:如果您希望每 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;
}

if you want your code to be executed every hour (ie 1:00, 2:00, 3:00) you can create a timer with some small interval (let's say a second, depends on precision you need) and inside that timer event check if an hour has passed如果您希望您的代码每小时执行一次(即 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..
     }

}

I agree with Señor Salt that the chron job should be the first choice.我同意 Señor Salt 的意见,认为 chron 工作应该是首选。 However, the OP asked for every hour on the hour from c#.但是,OP 从 c# 每小时要求每小时一次。 To do that, I set up the first timed event to fire on the hour:为此,我将第一个定时事件设置为在整点触发:

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();

The problem now is that if the above timer.Interval happens to be 45 minutes and 32 seconds, then the timer will continue firing every 45:32 not just the first time.现在的问题是,如果上面的 timer.Interval 恰好是 45 分 32 秒,那么计时器将每隔 45:32 继续触发,而不仅仅是第一次。 So, inside the timer_Tick method, you have to readjust the timer.Interval to one hour.因此,在 timer_Tick 方法中,您必须将 timer.Interval 重新调整为一小时。

 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();
 }

Just a small comment based on /Anarion's solution that I couldn't fit into a comment.只是基于 /Anarion 的解决方案的一个小评论,我无法发表评论。

you can create a timer with some small interval (let's say a second, depends on precision you need)您可以创建一个间隔很小的计时器(假设一秒钟,取决于您需要的精度)

You don't need it to go with any precision at all, you're thinking "how do I check this hour is the hour I want to fire".你根本不需要它的精确度,你在想“我如何检查这个时间是我想要开火的时间”。 You could alternatively think "How do I check the next hour is the hour I want to fire" - once you think like that you realise you don't need any precision at all, just tick once an hour, and set a thread for the next hour.您也可以考虑“我如何检查下一个小时是我要开火的小时”-一旦您这样想,您就会意识到根本不需要任何精度,只需每小时打勾一次,然后为下一个小时。 If you tick once an hour you know you'll be at some point before the next hour.如果您每小时打勾一次,您就知道您将在下一小时之前的某个时间点。

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)

Use a Cron Job on the server to call a function at the specified interval使用服务器上的 Cron Job 以指定的时间间隔调用函数

Heres a link http://www.thesitewizard.com/general/set-cron-job.shtml这是一个链接http://www.thesitewizard.com/general/set-cron-job.shtml

How about something simpler?更简单的东西怎么样? Use a one-minute timer to check the hour:使用一分钟计时器检查小时:

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

What about trying the below code, the loop is determined to save your resources, and it is running every EXACT hour, ie with both minutes and seconds (and almost milliseconds equal to zero:试试下面的代码怎么样,循环是为了节省你的资源,它每精确小时运行一次,即分钟和秒(几乎毫秒等于零:

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

Why is everyone trying to handle this problem with a timer?为什么每个人都试图用计时器来处理这个问题?

you're doing two things... waiting until the top of the hour and then running your timer every hour on the hour.你正在做两件事......等到小时,然后每小时运行你的计时器。

I have a windows service where I needed this same solution.我有一个 Windows 服务,我需要同样的解决方案。 I did my code in a very verbose way so that it is easy to follow for anyone.我以非常冗长的方式编写了代码,以便任何人都可以轻松理解。 I know there are many shortcuts that can be implemented, but I leave that up to you.我知道有很多捷径可以实现,但我把它留给你。

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;
}         

Here's a simple, stable (self-synchronizing) solution:这是一个简单、稳定(自同步)的解决方案:

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);
}

Note that iterations may be skipped if DoStuff() takes longer than an hour to execute.请注意,如果DoStuff()执行时间超过一个小时,则可能会跳过迭代。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM