14

我想每小时执行一个方法。我写了一些代码,但这还不够我的目标。下面的代码每 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 
}
4

8 回答 8

33

如果您希望您的代码每 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..
     }

}
于 2013-10-10T09:30:24.557 回答
8

我同意 Señor Salt 的观点,即计时工作应该是首选。但是,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();

现在的问题是,如果上面的 timer.Interval 恰好是 45 分 32 秒,那么计时器将继续每 45:32 触发一次,而不仅仅是第一次。因此,在 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();
 }
于 2014-12-08T18:25:04.880 回答
5

只是基于 /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)
于 2014-03-05T16:10:05.707 回答
2

更简单的东西怎么样?使用一分钟计时器检查小时:

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
    }
}
于 2017-02-10T21:41:24.297 回答
1

使用服务器上的 Cron Job 以指定的时间间隔调用函数

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

于 2013-10-10T09:26:29.303 回答
0

为什么每个人都试图用计时器来处理这个问题?

您正在做两件事……等到整点钟,然后每小时整点运行一次计时器。

我有一个 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;
}         
于 2018-12-05T20:07:48.403 回答
0

试试下面的代码怎么样,循环是为了节省你的资源,它每隔一小时运行一次,即分钟和秒(几乎毫秒等于零:

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
            }
        }
    }
}
于 2017-01-17T08:24:52.530 回答
0

这是一个简单、稳定(自同步)的解决方案:

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()执行时间超过一小时,则可能会跳过迭代。

于 2019-07-03T12:25:16.847 回答