为了更好地理解,我将以DHCP租约的简单抽象为例:租约包含IP和MAC地址,它被授予的时间,并且可以在给定的时间跨度内更新。一旦过期,将调用一个事件。同样,这只是我能想出的最小的例子:
using System;
using System.Net;
using System.Net.NetworkInformation;
using System.Timers;
namespace Example
{
public class Lease
{
public IPAddress IP
{
get;
private set;
}
public PhysicalAddress MAC
{
get;
private set;
}
public DateTime Granted
{
get;
private set;
}
public event EventHandler Expired;
private readonly Timer timer;
public Lease(IPAddress ip, PhysicalAddress mac, TimeSpan available)
{
IP = ip;
MAC = mac;
timer = new Timer();
timer.AutoReset = false;
timer.Elapsed += timerElapsed;
Renew(available);
}
public void timerElapsed(object sender, EventArgs e)
{
var handle = Expired;
if (handle != null)
{
handle(this, EventArgs.Empty);
}
}
public void Renew(TimeSpan available)
{
Granted = DateTime.Now;
timer.Interval = available.TotalMilliseconds;
timer.Enabled = true;
}
}
}
创作时有什么需要考虑 - 例如 - "几千"这样一个类的实例?我最关心的是计时器。 我应该考虑这样一个任务的另一种设计模式(比如所有租约的经理,或者根本不使用计时器?)或者在创建大量计时器时没有什么可担心的,这是适当的方式吗?至少我总是试图在计时器和事件时保持谨慎。
答案 0 :(得分:2)
您可以只存储每个Lease
对象的到期时间,而不是创建数千个计时器,然后定期查找过期的对象。
在我的头部代码示例的顶部:
var leases = new List<Lease>();
var running = true;
var expiredChecker = Task.Factory.StartNew(() =>
{
while (running)
{
var expired = leases.All(l => l.ExpirationDate < DateTime.Now);
// do something with the expired lease objects
}
});
假设您的IEnumerable<Lease>
对象上有一个名为DateTime
的{{1}} ExpirationDate
属性,则可以通过在要停止时将运行设置为false来取消此属性
答案 1 :(得分:1)
根据System.Timers.Timer
MSDN page:
基于服务器的Timer设计用于a中的工作线程 多线程环境。服务器计时器可以在线程之间移动 处理凸起的Elapsed事件,导致更准确 Windows计时器按时提升事件。
这意味着当您同时运行几千个计时器时,不太可能导致问题。
这并不意味着这是一个好方法,你应该寻找一个更集中的解决方案来解决这个问题。
答案 2 :(得分:1)
我建议使用System.Threading.Timer
代替System.Timers.Timer
。第二个是关于第一个在设计时可见的包装器,如果你真的不需要设计时间支持则没有必要。 Timer内部调用ThreadPool.QueueUseWorkItem ,而线程池负责维护计时器tick上的线程。 线程池只使用一个线程来维护所有的定时器对象,并且该线程决定每个定时器队列在计时器上的新线程时刻录。
我不能看到任何的开销,除非你的计时器打得如此之快,以至于你无法在tick工作中完成所有操作而只是在线程池中排队太多工作。
答案 3 :(得分:1)
我认为这部分取决于您在服务器上可用的资源,以及您需要的准确性和性能。
另一种方法可能是在每个实例中存储像时间戳一样简单的东西,并定期检查该值,将其与当前时间进行比较,并适当地更新它。我预感到可能在性能上更容易 - 但你应该尝试以某种方式对它进行基准测试以确定。
当然,如果你有大量的实例,迭代所有实例可能也需要一些时间,所以可能将这些组合成组,其中每个组在常规(可调节?)间隔的单独线程中处理可能是一个选择。
如果没有关于性能的一些信息,在这里给出一个很好的答案有点困难,所以你应该只是创建一个概念证明,并测试你认为可能有用的几个策略,并尝试对它们进行基准测试看哪个最合适。