我有一个对象,我想延迟一个操作。我为此做了两个不同的实现。第一个使用System.Threading.Timer来延迟我的操作,而第二个使用静态线程和到期日期。 Personnaly,我更喜欢第一种方法,但如果使用Timer而不是托管线程有任何开销,我就会徘徊。
首次实施:
class ThingWithDelayedClose
{
private Action<ThingWithDelayedClose> _closeCallback;
public ThingWithDelayedClose(string key, Action<ThingWithDelayedClose> closeCallback)
{
this.Key = key;
_closeCallback = closeCallback;
Console.WriteLine("Object created: " + this.Key);
}
public string Key { get; private set; }
public void RequestClose()
{
Console.WriteLine("Close requested: " + this.Key);
dynamic state = new ExpandoObject();
state.Timer = new Timer(new TimerCallback(this.TimerCallback), state, 2000, Timeout.Infinite);
}
private void TimerCallback(dynamic state)
{
using ((Timer)state.Timer)
{
_closeCallback(this);
Console.WriteLine("Object closed: " + this.Key);
}
}
}
第二次实施:
class ThingWithDelayedClose
{
static List<ThingWithDelayedClose> s_instances;
static ThingWithDelayedClose()
{
s_instances = new List<ThingWithDelayedClose>();
new Thread(() =>
{
// I know that I would need to change this in a real world app
while (true)
{
lock (s_instances)
{
var now = DateTime.Now;
var removeList = new List<ThingWithDelayedClose>();
foreach (var instance in s_instances)
{
if (instance._closedTime <= now)
{
instance.Close();
removeList.Add(instance);
}
}
removeList.ForEach(p => s_instances.Remove(p));
}
Thread.Sleep(1000);
}
}).Start();
}
private DateTime _closedTime = DateTime.MaxValue;
private Action<ThingWithDelayedClose> _closeCallback;
public ThingWithDelayedClose(string key, Action<ThingWithDelayedClose> closeCallback)
{
this.Key = key;
_closeCallback = closeCallback;
Console.WriteLine("Object created: " + this.Key);
lock (s_instances)
{
s_instances.Add(this);
}
}
public string Key { get; private set; }
public void RequestClose()
{
Console.WriteLine("Close requested: " + this.Key);
_closedTime = DateTime.Now.Add(TimeSpan.FromSeconds(2.0d));
}
private void Close()
{
_closeCallback(this);
Console.WriteLine("Object closed: " + this.Key);
}
}
答案 0 :(得分:1)
使用计时器比旋转新线程便宜得多。
根据您要完成的任务,您可以使用System.Threading
中的一个内置同步原语,使其更快(更简单,更安全)。
答案 1 :(得分:0)
只要您只讨论一个线程,使用Timer会更便宜,但如果您有多个操作,则第二个实现会更好,因为每个Timer.Elapsed实际上是在不同的线程上运行。
答案 2 :(得分:0)
Timer的开销远低于Thread的开销。创建(以及切换到和来自)线程需要同步,特别是在多个处理器的情况下,这是非常昂贵的操作。
另外,请考虑您的线程示例在主线程之外的单独线程中回调,这要求所有客户端也是线程感知的。
答案 3 :(得分:0)
线程创建起来很昂贵,并且保留起来有些昂贵。如果一个人有一个可以执行的工作,可以用进入的单个方法来描述,做一些事情,并且相当快地退出,创建一个全新的线程,用它执行一些工作,然后放弃它可能是浪费。在许多情况下,保持线程一段时间会更有效,看看是否需要一个线程用于其他快速工作;如果出现这种需要,则可以由第一个线程处理该作业,而不必创建新的线程。 .net Framework提供了一个称为线程池的系统,用于使用适量的可重用线程自动分派短作业。请注意,线程池将同时分派的线程数量有限;如果工作提交的速度快于完成工作,则以后的工作必须等到早期工作完成。出于这个原因,长时间运行的作业,特别是涉及大量“等待”的作业,不应该使用线程池。
如果要执行的工作需要很长时间才能完成,则可以创建新线程并在那里运行作业。这可能比线程池好得多,特别是如果这项工作需要大量的等待。另一方面,每个活动线程,即使只是“等待”的线程,也会占用大量内存,否则这些内存可用于其他事情。在某些情况下,使用新线程的简单性可能是值得的。另一方面,有许多场景可以通过其他方式更便宜地处理,例如使用计时器。
实际上,一个计时器对象请求一旦经过足够的时间,表单的线程(在Forms计时器的情况下)或线程池线程(用于系统计时器)应该运行指定的代码段。如果一个人可以很容易地在一个对象中封装代码所需的所有信息,那么计时器比一个线程要便宜得多。线程最有用的地方是,当一个人必须模拟一系列复杂的事件,并且为计时器和其他此类对象执行所需操作所需的所有必要信息将比简单地使用更加复杂和繁琐。单线程中的“直线”代码,用于执行相同的工作。