繁体   English   中英

与thread.sleep一起使用时如何在无限循环中执行多个任务

[英]How to do multiple tasks in an infinite loop while using with thread.sleep

我想每天早上4:00 AM执行一个.exe。 我使用以下代码进行了此操作。

  while (true)
  {
      var now = DateTime.Now;
      var schedule = new DateTime(now.Year, now.Month, now.Day, 4, 00, 00);
      if (schedule < now) schedule = schedule.AddDays(1);

      Thread.Sleep(schedule.Subtract(now));

      Process.Start("sample.exe");
  }

现在,我想执行另一个任务,例如每天晚上1:00 AM删除特定的文件夹和子文件夹。 因此,对于删除,我将使用类似

Directory.Delete(folder_path, recursive: true);

我应该使用相同的无限循环还是以其他方式实现它?

您不应将Thread.Sleep用于计时。 尝试避免Thread.Sleep。 如果中止该线程,则只能中断睡眠。 更好的方法是ManualResetEvent.Wait() ,可以通过设置它来中断它。


我的建议是,使用计时器:

创建用于检查作业列表的计时器。 添加下一次在作业上执行。 计时器不会阻止MainThread,因此您可以安全地终止应用程序。 您可以每分钟或更长时间检查一次作业(间隔)。

伪装!!

class MyJob
{
    public DateTime ExecuteTime { get; set; }
    public Action Action { get; set; }
}

List<MyJob> Jobs = new List<MyJob>();

public void TimerCallback(object sender, EventArgs e)
{
    foreach (var job in Jobs)
    {
        if (job.ExecuteTime <= DateTime.Now)
        {
            try
            {
                job.Action();
            }
            catch(Exception exception)
            {
                // log the exception..
            }
            finally
            {
                job.ExecuteTime = job.ExecuteTime.Add(TimeSpan.FromDays(1));
            }
        }
    }
}

// this AddJob checks if the first execute should be today or tomorrow
public void AddJob(TimeSpan executeOn, Action action)
{
    var now = DateTime.Now;

    var firstExec = new DateTime(now.Year, now.Month, now.Day, 4, 0, 0);

    if (firstExec < now)  // time for today is already passed, next day..
        firstExec = firstExec.Add(TimeSpan.FromDays(1));

    Jobs.Add(new MyJob { ExecuteTime = firstExec, Action = action });
}

public void Add()
{
    // Add the jobs.
    AddJob(new TimeSpan(4, 0, 0), RunMyJob);
    AddJob(new TimeSpan(5, 0, 0), RunMyJob2);
}

public void RunMyJob()
{
    // delete or move, whatever...
}

public void RunMyJob2()
{
    // delete or move, whatever...
}

如果您要做的只是计划一个.exe,则可以使用Windows Task Scheduler-它比您自己尝试做要容易得多。 如果需要在几个不同的时间完成多个任务,则可以创建多个.exe。 (很抱歉,我正在用手机写这篇文章)。

我将为此使用Microsoft的Reactive Framework(NuGet“ System.Reactive”)。

然后,您可以编写以下方便的辅助方法:

public IDisposable ScheduleDaily(TimeSpan when, Action what)
{
    var now = DateTime.Now;
    var schedule = now.Date.Add(when);
    if (schedule < now)
    {
        schedule = schedule.AddDays(1.0);
    }

    return
        Observable
            .Timer(schedule, TimeSpan.FromDays(1.0))
            .Subscribe(_ => what());
}

要调用它,只需执行以下操作:

IDisposable runSample = ScheduleDaily(TimeSpan.FromHours(4.0),
    () => Process.Start("sample.exe"));

IDisposable deleteFolders = ScheduleDaily(TimeSpan.FromHours(1.0),
    () => Directory.Delete(folder_path, recursive: true));

ScheduleDaily返回一个方便的IDisposable ,您可以使用.Dispose()停止计时器。

无需线程或睡眠。 很简单。

Thread.Sleep()导致当前线程进入睡眠状态,因此该线程在进入睡眠状态之前不会再次执行任何操作(除非您中断它或进行其他操作)。

因此,如果您这样做,则只需要更多线程即可。

var scheduleLoopAction = new Action<int, int, string>((int hour, int minute, string processName) =>
{
    while (true)
    {
        var now = DateTime.Now;
        var schedule = new DateTime(now.Year, now.Month, now.Day, hour, minute, 00);
        if (schedule < now) schedule = schedule.AddDays(1);

        System.Threading.Thread.Sleep(schedule.Subtract(now));

        System.Diagnostics.Process.Start(processName);
    }
});

((new System.Threading.Thread(() => { scheduleLoopAction(4, 0, "sample.exe"); }))).Start();
((new System.Threading.Thread(() => { scheduleLoopAction(1, 0, "sample2.exe"); }))).Start();

这可能不是实现目标的最佳方法,但我认为您想要的是问题中的内容。

请注意,线程调用不会阻塞,因此该方法将立即完成(与问题中的示例不同,它将永远存在)。 如果要阻止它,则可以在当前线程中运行最后一个调度,例如

((new System.Threading.Thread(() => { scheduleLoopAction(4, 0, "sample.exe"); }))).Start();
scheduleLoopAction(1, 0, "sample2.exe");  // Runs in current thread

暂无
暂无

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

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