C# net线程中的计时器
我希望在新线程中有一个计时器计时/已用事件。似乎我不能使用Windows计时器。但是如果我使用Timers.Timer,它会从线程池中为每个经过的事件创建工作线程。有没有办法使这些事件发生在同一个线程中 更新: 谢谢大家回答这个问题 不过,我在整件事背后的意图可能听起来有点疯狂。我要你纠正我。这是我的想法,作为一个新手,当我尝试去做这件事的时候。我正在尝试每2秒执行一项任务。当我使用Timers.Timer时,它每2秒创建一个线程,我认为这是一种开销 我的主线程和其他线程需要大量处理器时间来执行它们的任务。所以,如果我可以避免创建这些线程,我就可以节省处理器的任何微秒,以便在每次计时器运行时为我的主线程和其他线程创建一个线程 我做了一个快速测试,比较了几个解决方案。每种情况下的间隔为1000毫秒。100滴答 解决方案1:具有等待/睡眠{00:01:42.0068344}的无限循环 解决方案2:使用Brian的同步器{00:01:42.4068573} 解决方案3:计时器。计时器的原样{00:01:42.4018571} 这应该告诉我,2.0068344、2.4068573、2.4018571是为背景中的其他事情而浪费的时间,而不是100个滴答声的1000毫秒的时间间隔。这意味着,当解决方案1满足您的需求时,它将是性能最佳的解决方案 这还意味着,尽管Brian的解决方案是同步到一个线程的,但它实际上是在后台创建线程 请确认或更正 有没有办法使这些事件发生在同一个线程中 不,那也没什么意义。 事件不能只是“闯入”到线程,线程必须合作 您可以做的是创建一个线程,该线程重复循环并等待信号量。然后使用任何类型的计时器来触发该信号量 是的。您可以使System.Timers.Timer在同一线程中执行已用事件处理程序。为此,需要将SynchronizingObject属性设置为将封送执行到所选线程的对象。然而,重要的是要认识到,不能只将执行注入到随机线程中。接收线程必须专门设计为允许封送方法调用的执行C# net线程中的计时器,c#,.net,multithreading,timer,C#,.net,Multithreading,Timer,我希望在新线程中有一个计时器计时/已用事件。似乎我不能使用Windows计时器。但是如果我使用Timers.Timer,它会从线程池中为每个经过的事件创建工作线程。有没有办法使这些事件发生在同一个线程中 更新: 谢谢大家回答这个问题 不过,我在整件事背后的意图可能听起来有点疯狂。我要你纠正我。这是我的想法,作为一个新手,当我尝试去做这件事的时候。我正在尝试每2秒执行一项任务。当我使用Timers.Timer时,它每2秒创建一个线程,我认为这是一种开销 我的主线程和其他线程需要大量处理器时间来执行
public static void Main(string[] args)
{
var timer = new System.Timers.Timer();
timer.Interval = 1000;
timer.Elapsed +=
(s, a) =>
{
Console.WriteLine("{1} {0}",
DateTime.Now, Thread.CurrentThread.ManagedThreadId);
};
timer.SynchronizingObject = new Synchronizer();
timer.Start();
Console.ReadLine();
}
这是同步器类的代码。此代码使用.NETBCL的4.0中的类。如果你不使用4.0,那么你可以用Stephen Toub的代替
更新:
您需要了解System.Timers.Timer的工作原理。它实际上在后台使用System.Threading.Timer,并在线程池线程上执行事件处理程序。因此,它实际上根本没有创建任何线程。线程池中的相同线程被一次又一次地回收。没有线程创建开销。这就是线程池的全部要点
现在,我在这里提供的解决方案仍然在幕后使用ThreadPool,但不是让工作项直接执行经过的事件处理程序,而是执行Synchronizer.BeginInvoke方法,该方法将事件处理程序封送到同步器创建的线程上
因此,毫不奇怪,我在这里提供的解决方案会更慢。就个人而言,我会坚持解决方案1,因为它更容易。在这一点上,我不会太担心性能。如果希望在特定线程上执行定时事件,至少有两个选项: 旋转你想让“计时器”运行的线程,让它在计时器持续时间内睡眠,然后做你想让它做的工作。 让线程等待计时器发出信号的事件。这似乎是执行上述操作的一种更复杂的方法,但如果您希望线程能够通过计时器以外的方式被唤醒,那么这可能是有意义的。
我认为提供另一个答案是有益的。原因是我的另一个答案太复杂了。如果您只想确保在同一个线程上定期执行任务,那么就没有必要在System.Timers.Timer实例上设置SynchronzingObject属性。启动一个在无限循环中旋转的新线程要容易得多,该循环执行您最初在已用事件中放置的内容
我建议您创建一个线程来监视由计时器的已用事件处理程序提供的阻塞队列。那么事件处理程序使用哪个线程就无关紧要了,因为它所做的只是将一些东西放入队列中,所以该线程的持续时间将很短
要获得良好的阻塞队列实现,请参阅Marc Gravell的回答:。我很困惑。首先,您询问如何在新线程中运行代码。然后你说你想在同一个线程上执行。是哪一个!?很抱歉我不清楚
足够地计时器。计时器似乎为每个事件创建一个新线程。。我想要的是在一个新线程中运行代码。。但是所有这些事件都应该发生在同一个新的线程中,而不是为每个事件创建一个线程。也许你可以重新表述你的问题来解释你试图实现的目标。例如,我如何定期进行一些处理,但在任何给定时刻只允许一个线程处理这些数据?您是否使用WinForms或WPF并希望计时器使用UI线程?@user:没有C.net,只有C和.NETNice,我编辑了writeline以强调证明。请随意回滚这种魔法并不存在,它只能在线程是UI线程的情况下工作。只有该线程有一个由消息循环实现的同步提供程序。其他线程将使用默认提供程序,该提供程序将使用线程池线程。最好使用System.Windows.Forms。Timer@Hans当前位置我不确定我是否会将这个答案中的任何东西归类为魔法本身,但不管它被称为什么,它都会起作用。Synchronizer类是同步提供程序,它创建一个独立于UI线程的线程来执行这样的操作。我认为OP对System.Windows.Forms.Timer不感兴趣,因为它在UI线程上引发了不需要的事件;至少我是这样理解这个问题的。当然,尽管如此,我不会用我在这里提供的解决方案来解决这个问题,但严格来说,我相信它回答了这个问题。我刚刚阅读了问题附带的注释,OP确认了一个解决方案,即每次从UI线程分离时,在同一个线程上发生System.Timers.Timer.Appeased事件。Brian,您的两个解决方案对我都有效。这就是我想要的。工作和睡眠的方法必须不断地重新调整。
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); }
}
}
}
public static void Main(string[] args)
{
var stop = new ManualResetEvent(false);
var thread = new Thread(
() =>
{
while (stop.WaitOne(YOUR_INTERVAL_GOES_HERE))
{
// The code that was in the Elapsed event handler goes here instead.
}
});
Console.WriteLine("Press ENTER to stop...");
Console.ReadLine();
stop.Set();
thread.Join();
}