C#程序耗尽了太多的CPU?

时间:2012-04-09 08:46:27

标签: c# performance loops timer cpu

我有一个程序,在3个不同的计时器之间不断开始玩。

我的应用程序的主线程有一个while循环,它不断检查全局变量是否已设置为true,如果有,它将停止一个计时器并启动另外两个 - 一个连续,另一个自动停止无论出于何种原因,它都没有被命令停止。

这个while循环的条件为(1 == 1),因此它可以永久运行。

在任务管理器(XP)中,我看到我的程序在一个或多或少闲置的系统上占用了50%的CPU。

有没有办法通过降低while循环的速度来减少这个数字?

感谢。

7 个答案:

答案 0 :(得分:11)

  

有没有办法通过降低while循环的速度来减少这个数字?

停止忙碌的循环。有更好的方法来协调线程之间的事件。考虑使用Monitor.Wait / PulseAutoResetEvent / ManualResetEvent。基本上,设置全局变量的线程应该表明它已经完成了。或者,如果您的主线程不会执行任何 else,为什么不添加正常的C#事件,以便每当更改变量时,都会引发事件并采取相应的操作?

答案 1 :(得分:6)

您的程序执行busy waiting,这是一种不好的做法。您应该更改逻辑,以便阻止某种同步原语(也称为wait handle)而不是循环。

阻止等待句柄不是UI线程的选项,因此你必须总共创建三个线程并实现这样的方案:

  1. UI线程根本不关心其他线程。没有循环,没有睡觉,没有阻塞。
  2. 新的“控制器”线程将启动现有的“工作”线程,然后立即阻止(例如,在未发信号的事件上)。它将保持这种状态,不消耗CPU,直到事件发出信号(即“工人”完成)。
  3. “工人”主题会运行,然后发出事件信号。

答案 2 :(得分:4)

  

有没有办法通过降低while循环的速度来减少这个数字?

是的,您可以拨打Thread.Sleep(n)的电话。粒度为~20 ms。

但更好的选择是使用Waithandle 你的主线程将在句柄上等待,定时器代码的结束将指示它唤醒。

答案 3 :(得分:2)

您需要在给定的ms数内睡眠威胁。查看Thread.sleep()函数并将其放在while循环中。

答案 4 :(得分:2)

减慢这样的循环的最简单方法是添加一个System.Threading.Thread.Sleep(100);对于每次迭代,进程将休眠100毫秒,并且不再使用50%的cpu。

答案 5 :(得分:2)

你可以使用Threads代替Timer,它比Thread更昂贵。或者请检查在开始另一个之前停止的时间的线程状态。您可以通过减少代码逻辑来提高性能。

希望这会对你有所帮助。 :)

答案 6 :(得分:0)

虽然这里的答案并没有错,但它们并没有真正解决许多while(true)循环的问题,这就是while(1==1)

首先,即使循环在您的应用程序正在使用的整个时间运行,您仍然希望在某个时刻将其丢弃,例如当用户退出应用程序时,因为如果您有一个具有常量循环的线程即使用户关闭了UI窗口,该过程仍将保留,直到线程退出(永远不会出现真正的循环),或者直到用户变得明智并从任务管理器关闭它。

你可以通过在while循环中引用一个可访问属性的while条件检查来设置一个真正的条件来解决这个问题。

示例:

private bool RequestExit = false;
private Thread MyLoopThread;
private void MyLoop()
{
  while (!RequestExit)
  {
    //Do stuff!
    Sleep(1);
  }
}
public void StartLoop()
{
  RequestExit = false;
  MyLoopThread = new Thread(MyLoop);
  MyLoopThread.Start();
}
public void StopLoop()
{
  RequestExit = true;
}

这是愚蠢的,甚至不会避免双重启动或双重关闭事件。

更简洁的方法是设置一个你想要池的任意间隔,10ms左右应该对几乎任何实时事件都很好,并触发一个方法以该间隔触发。

private Timer DoStuffTimer;
private void DoStuffMethod(object obj = null)
{
  //Do stuff!
}
public void StartLoop()
{
  DoStuffTimer = new Timer(DoStuffMethod,null,10,10);
}
public void StopLoop()
{
  DoStuffTimer.Dispose();
}