![](/img/trans.png)
[英]Multiple threads with infinite loop and thread.sleep high CPU usage
[英]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.