0

我创建了一个应用程序,用于以特定间隔读取邮箱。如果有新邮件,它会下载附件创建 pdf 文件,例如 100 + 将其合并并将其邮寄回特定列表。由于某些服务器策略可以将其转换为窗口服务。我使用了一个计时器,我的代码如下

private System.Threading.Timer timer;
timer = new System.Threading.Timer(TimerTick, null, TimeSpan.Zero, TimeSpan.FromMinutes(1));

void TimerTick(object state)
{
  var minute = DateTime.Now.Minute;
  if (minute != lastMinute && minute % 5 == 0)
  {
    //check mail here
  }
}

实现这样的计时器是一种有效的方法吗?有没有更好的方法来处理这个?我担心性能,因为应用程序需要运行 24 x7,因此如果效率低下,最终可能会使用更多的 cpu 内存。

在这种情况下,计时器是唯一的最佳选择吗?

4

4 回答 4

4

您应该监控服务的性能。如果您发现存在性能问题:

  1. 测量它
  2. 更改您的代码
  3. 再次测量
  4. 而不是比较你的测量结果

System.Threading.Timer是一个简单的轻量级计时器,它使用回调方法并由线程池线程提供服务。

  • 您可能会考虑System.Timers.Timer使用基于服务器的计时器功能。

可维护性和调试提示:

  • 使用 XML 配置文件设置间隔,无需更改代码。这只会让您或管理员控制服务。

使用代码轻松调试您的服务:

static void Main()
{
#if (!DEBUG)
    System.ServiceProcess.ServiceBase[] ServicesToRun;
    ServicesToRun = new System.ServiceProcess.ServiceBase[] { new Service1() };
    System.ServiceProcess.ServiceBase.Run(ServicesToRun);
#else
    // Debug code: this allows the process to run as a non-service.
    // It will kick off the service start point, but never kill it.
    // Shut down the debugger to exit
    Service1 service = new Service1();
    service.EntryMethodHere(); // Your method that activates your timer
    // Put a breakpoint on the following line to always catch
    // your service when it has finished its work
    System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
#endif 
}
于 2012-10-24T19:51:05.380 回答
2

简单地给计时器一个 5 分钟的周期,而不是 1 分钟的周期并每 5 次检查一次邮件会更有效。

timer = new System.Threading.Timer(TimerTick, null, TimeSpan.Zero, TimeSpan.FromMinutes(5)); 
于 2012-10-24T19:35:12.003 回答
2

计时器非常高效,但也许您应该改用 TimeSpan.FromMinutes(5) 并删除 TimerTick 中效率低下的条件。由于 TimerTick 将在 ThreadPool 线程中运行,因此您必须在再次检查邮件服务器之前检查前一个事件是否已完成。

private System.Threading.Timer timer = new System.Threading.Timer(TimerTick, null, TimeSpan.Zero, TimeSpan.FromMinutes(5));

private bool FCheckingMails = false;
void TimerTick(object state)
{
    if (FCheckingMails) return;
    FCheckingMails = true;
    try
    {
        //check mail here
    }
    finally
    {
        FCheckingMails = false;
    }
}

有人可能会说 FCheckingMails 不是线程安全的,但它确实不需要。

如果您担心效率,您应该检查运行数百万次/分钟的代码,而不是运行 12 次/小时的代码。

祝你的任务好运。

于 2012-10-24T20:15:13.740 回答
0

System.Threading.Timer 在 CPU 和内存使用方面应该非常轻量级,所以我不会设想那里有任何问题。更一般地说,这种工作通常由调度程序触发,该调度程序可以配置更多的控制,并了解周末、一个月中的某天(例如,在每个月的第一天或最后一天进行处理)等。

如果您确实走这条路,那么请查看Quartz.Net,一个开源的 .net cron 作业调度程序。

于 2012-10-26T13:21:12.103 回答