最重要的说明:根据我的意见,我猜可能都在使用解决方案with this note确实在我的应用程序中我试图将它们结合起来。顺便说一下,你可以向我询问详细信息。
前注2:顺便说一下,由于SO不同于MSO downvotes或close close鼓励删除问题,我不会,否则所有有价值的评论和答案都将被删除。这是一个帮助并尝试互相理解的地方
这是linqpad代码的4种不同实现中最基本的。除了首先,所有其他人都给出了所需的输出。
你能解释一下这些细节吗?
由于我的应用程序中有许多计时器,我需要管理和同步,以最佳方式使用完整代码以及替代解决方案的优缺点
没有SynchronizingObject,也没有定时器停止/启动也没有锁定
System.Timers.Timer timer2 = new System.Timers.Timer(100);
int i = 0;
void Main()
{
timer2.Elapsed += PromptForSave;
timer2.Start();
}
private void PromptForSave(Object source, System.Timers.ElapsedEventArgs e)
{
i = i + 1;
Thread.Sleep(new Random().Next(100, 1000));
Console.WriteLine(i);
}
给出:
4 5 6 7 8 9 11 12 13 14 15 15 15 17 18 20 21 22
使用SynchronizingObject:
void Main()
{
timer2.Elapsed += PromptForSave;
timer2.SynchronizingObject = new Synchronizer();
timer2.Start();
}
private void PromptForSave(Object source, System.Timers.ElapsedEventArgs e)
{
i = i + 1;
Thread.Sleep(new Random().Next(100, 1000));
Console.WriteLine(i);
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
使用计时器启动/停止
void Main()
{
timer2.Elapsed += PromptForSave;
timer2.Start();
}
private void PromptForSave(Object source, System.Timers.ElapsedEventArgs e)
{
timer2.Stop();
i = i + 1;
Thread.Sleep(new Random().Next(100, 1000));
Console.WriteLine(i);
timer2.Start();
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
最后带锁
object lockForTimer = new object();
void Main()
{
timer2.Elapsed += PromptForSave;
timer2.Start();
}
private void PromptForSave(Object source, System.Timers.ElapsedEventArgs e)
{
lock(lockForTimer){
i = i + 1;
Thread.Sleep(new Random().Next(100, 1000));
Console.WriteLine(i);
timer2.Start();
}
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Syncronizer看起来像:
public class Synchronizer : ISynchronizeInvoke
{
private Thread m_Thread;
private BlockingCollection<Message> m_Queue = new BlockingCollection<Message>();
public Synchronizer()
{
m_Thread = new Thread(Run);
m_Thread.IsBackground = true;
m_Thread.Start();
}
private void Run()
{
while (true)
{
Message message = m_Queue.Take();
message.Return = message.Method.DynamicInvoke(message.Args);
message.Finished.Set();
}
}
public IAsyncResult BeginInvoke(Delegate method, object[] args)
{
Message message = new Message();
message.Method = method;
message.Args = args;
m_Queue.Add(message);
return message;
}
public object EndInvoke(IAsyncResult result)
{
Message message = result as Message;
if (message != null)
{
message.Finished.WaitOne();
return message.Return;
}
throw new ArgumentException("result");
}
public object Invoke(Delegate method, object[] args)
{
Message message = new Message();
message.Method = method;
message.Args = args;
m_Queue.Add(message);
message.Finished.WaitOne();
return message.Return;
}
public bool InvokeRequired
{
get { return Thread.CurrentThread != m_Thread; }
}
private class Message : IAsyncResult
{
public Delegate Method = null;
public object[] Args = null;
public object Return = null;
public object State = null;
public ManualResetEvent Finished = new ManualResetEvent(false);
public object AsyncState
{
get { return State; }
}
public WaitHandle AsyncWaitHandle
{
get { return Finished; }
}
public bool CompletedSynchronously
{
get { return false; }
}
public bool IsCompleted
{
get { return Finished.WaitOne(0); }
}
}
}
答案 0 :(得分:1)
第四种解决方案(lock
)是危险的。由于每次都会在Elapsed
线程上引发ThreadPool
事件,并且您可能会同时阻止其中的许多线程,这可能会导致ThreadPool
增长(带来所有后果)。所以这个解决方案很糟糕。
第三种解决方案(开始/停止)将处理不是由计时器设置的速率的事件,而是处理取决于每个特定操作所花费的时间的速率。所以它可能会跳过&#34;很多事件。这个解决方案就像一个&#34;帧丢弃&#34;在视频流中。
第二个解决方案会将所有操作排入队列并且不会跳过它们。当动作的处理时间(几乎总是)长于计时器间隔时,它具有潜在的危险性。队列只会在某个时间增长导致OutOfMemoryException
。这个解决方案就像一个&#34;帧缓冲区&#34;在视频流中。
第一个应删除,只有问题。
因此,您应该在第二个和第三个解决方案之间进行选择,具体取决于您的用例的重要性:所有传入事件的可靠处理或具有最大吞吐量(速率)的处理。