CPU友好的无限循环
编写无限循环很简单:
while(true){
//add whatever break condition here
}
但这会降低 CPU 性能。该执行线程将尽可能多地消耗 CPU 的电量。
降低对 CPU 影响的最佳方法是什么? 添加一些 Thread.Sleep(n)
应该可以解决问题,但为 Sleep()
方法设置较高的超时值可能表明应用程序对操作系统无响应。
假设我需要在控制台应用程序中每分钟左右执行一项任务。 我需要保持 Main()
在“无限循环”中运行,同时计时器将触发完成这项工作的事件。我希望保持 Main()
对 CPU 的影响最小。
您建议采用什么方法。 Sleep()
可以,但正如我已经提到的,这可能表明线程对操作系统无响应。
稍后编辑:
我想更好地解释我正在寻找的内容:
我需要一个控制台应用程序而不是Windows服务。控制台应用程序可以使用 Compact Framework 模拟 Windows Mobile 6.x 系统上的 Windows 服务。
我需要一种方法,让应用程序在 Windows Mobile 设备运行时保持活动状态。
我们都知道,只要其静态 Main() 函数运行,控制台应用程序就会运行,因此我需要一种方法来防止 Main() 函数退出。
在特殊情况下(例如:更新应用程序),我需要请求应用程序停止,因此我需要无限循环并测试某些退出条件。例如,这就是为什么
Console.ReadLine()
对我来说没有用。没有退出条件检查。关于上述内容,我仍然希望 Main() 函数尽可能资源友好。抛开检查退出条件的函数的指纹不谈。
Writing an infinite loop is simple:
while(true){
//add whatever break condition here
}
But this will trash the CPU performance. This execution thread will take as much as possible from CPU's power.
What is the best way to lower the impact on CPU?
Adding some Thread.Sleep(n)
should do the trick, but setting a high timeout value for Sleep()
method may indicate an unresponsive application to the operating system.
Let's say I need to perform a task each minute or so in a console app.
I need to keep Main()
running in an "infinite loop" while a timer will fire the event that will do the job. I would like to keep Main()
with the lowest impact on CPU.
What methods do you suggest. Sleep()
can be ok, but as I already mentioned, this might indicate an unresponsive thread to the operating system.
LATER EDIT:
I want to explain better what I am looking for:
I need a console app not Windows service. Console apps can simulate the Windows services on Windows Mobile 6.x systems with Compact Framework.
I need a way to keep the app alive as long as the Windows Mobile device is running.
We all know that the console app runs as long as its static Main() function runs, so I need a way to prevent Main() function exit.
In special situations (like: updating the app), I need to request the app to stop, so I need to infinitely loop and test for some exit condition. For example, this is why
Console.ReadLine()
is no use for me. There is no exit condition check.Regarding the above, I still want Main() function as resource friendly as possible. Let asside the fingerprint of the function that checks for the exit condition.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
为了避免无限循环,只需使用
WaitHandle
即可。要让进程从外部世界退出,请使用带有唯一字符串的EventWaitHandle
。下面是一个例子。如果您第一次启动它,它会简单地每 10 秒打印一条消息。如果您同时启动该程序的第二个实例,它将通知其他进程正常退出并立即退出。此方法的 CPU 使用率:0%
To avoid the infinity loop simply use a
WaitHandle
. To let the process be exited from the outer world use aEventWaitHandle
with a unique string. Below is an example.If you start it the first time, it simple prints out a message every 10 seconds. If you start in the mean time a second instance of the program it will inform the other process to gracefully exit and exits itself also immediately. The CPU usage for this approach: 0%
您可以使用 System.Threading.Timer 类,它提供能够在给定时间段内异步执行回调。
作为替代方案,有 System.Timers.Timer 类公开已过事件,该事件在给定时间段内引发的时间已过。
You can use System.Threading.Timer Class which provides ability to execute callback asynchronously in a given period of time.
As alternative there is System.Timers.Timer class which exposes Elapsed Event which raises when a given period of time is elapsed.
为什么你会容忍使用无限循环?对于这个例子,将程序设置为计划任务,每分钟运行一次,不是更经济吗?
Why would you condone the use of an infinite loop? For this example would setting the program up as a scheduled task, to be run every minute, not be more economical?
为什么不编写一个小型应用程序并使用系统的任务调度程序每分钟、每小时等运行它?
另一种选择是编写一个在后台运行的 Windows 服务。该服务可以使用 MSDN 上的简单 Alarm 类,如下所示:
http://msdn.microsoft.com/en-us/library/wkzf914z%28v=VS.90%29.aspx#Y2400
您可以使用它定期触发您的方法。在内部,此 Alarm 类使用计时器:
http://msdn.microsoft .com/en-us/library/system.timers.timer.aspx
只需正确设置计时器的间隔(例如 60000 毫秒),它就会定期引发 Elapsed 事件。将事件处理程序附加到 Elapsed 事件以执行您的任务。无需仅仅为了保持应用程序的运行而实现“无限循环”。这由服务为您处理。
Why don't you write a small application and use the system's task scheduler to run it every minute, hour...etc?
Another option would be to write a Windows Service which runs in the background. The service could use a simple Alarm class like the following on MSDN:
http://msdn.microsoft.com/en-us/library/wkzf914z%28v=VS.90%29.aspx#Y2400
You can use it to periodically trigger your method. Internally this Alarm class uses a timer:
http://msdn.microsoft.com/en-us/library/system.timers.timer.aspx
Just set the timer's interval correctly (e.g. 60000 milliseconds) and it will raise the Elapsed event periodically. Attach an event handler to the Elapsed event to perform your task. No need to implement an "infinite loop" just to keep the application alive. This is handled for you by the service.
我为一个应用程序执行了此操作,该应用程序必须在文件拖放到文件夹时处理文件。最好的选择是在“main”末尾使用一个带有 Console.ReadLine() 的计时器(如建议的那样),而不放入循环。
现在,您担心告诉应用程序停止:
我也通过一些基本的“文件”监视器完成了此操作。只需在应用程序的根文件夹中创建文件“quit.txt”(通过我的程序或可能要求其停止的其他应用程序)将使应用程序退出。半代码:
OnNewFile 可能是这样的:
现在您提到这是(或可能)用于移动应用程序?您可能没有文件系统观察程序。在这种情况下,也许您只需要“终止”该进程(您说“在特殊情况下(例如:更新应用程序),我需要请求该应用程序停止”。无论停止它的“请求者”是谁,都应该只需杀死该进程即可)
I did this for an application that had to process files as they were dropped on a folder. Your best bet is a timer (as suggested) with a Console.ReadLine() at the end of "main" without putting in a loop.
Now, your concern about telling the app to stop:
I have also done this via some rudimentary "file" monitor. Simply creating the file "quit.txt" in the root folder of the application (by either my program or another application that might request it to stop) will make the application quit. Semi-code:
The OnNewFile could be something like this:
Now you mentioned that this is (or could be) for a mobile application? You might not have the file system watcher. In that case, maybe you just need to "kill" the process (you said "In special situations (like: updating the app), I need to request the app to stop". Whoever the "requester" to stop it is, should simply kill the process)
在我看来,您希望 Main() 进入可中断循环。要发生这种情况,必须在某个地方涉及多个线程(或者您的循环必须定期轮询;不过,我不在这里讨论该解决方案)。同一应用程序中的另一个线程或另一个进程中的线程必须能够向 Main() 循环发出它应该终止的信号。
如果这是真的,那么我认为您想要使用 ManualResetEvent 或 EventWaitHandle 。您可以等待该事件,直到它发出信号(并且信号必须由另一个线程完成)。
例如:
It sounds to me like you want Main() to enter an interruptable loop. For this to happen, multiple threads must be involved somewhere (or your loop must poll periodically; I am not discussing that solution here though). Either another thread in the same application, or a thread in another process, must be able to signal to your Main() loop that it should terminate.
If this is true, then I think you want to use a ManualResetEvent or an EventWaitHandle . You can wait on that event until it is signalled (and the signalling would have to be done by another thread).
For example:
您可以使用
Begin-/End-Invoke
来屈服于其他线程。例如,您可以这样使用它:
这使用了我机器上一个核心的 60%(完全空循环)。或者,您可以在正文中使用此(源)代码循环:
在我的机器上使用了 20% 的一个核心。
You can use
Begin-/End-Invoke
to yield to other threads. E.g.You would use it as such:
This used 60% of one core on my machine (completely empty loop). Alternatively, you can use this (Source) code in the body of your loop:
That used 20% of one core on my machine.
阐述 CodeInChaos 所做的评论:
您可以设置给定的 线程的优先级。线程根据其优先级调度执行。用于确定线程执行顺序的调度算法因操作系统而异。所有线程默认为“正常”优先级,但如果您将循环设置为低;它不应该从设置为正常的线程中窃取时间。
To expound on a comment CodeInChaos made:
You can set a given thread's priority. Threads are scheduled for execution based on their priority. The scheduling algorithm used to determine the order of thread execution varies with each operating system. All threads default to "normal" priority, but if you set your loop to low; it shouldn't steal time from threads set to normal.
Timer 方法可能是您最好的选择,但是既然您提到了 Thread.Sleep,就有一个有趣的 Thread.SpinWait 或 SpinWait struct 用于解决类似问题的替代方案,有时比短的更好Thread.Sleep 调用。
另请参阅此问题:Thread.SpinWait 方法的目的是什么?
The Timer approach is probably your best bet, but since you mention Thread.Sleep there is an interesting Thread.SpinWait or SpinWait struct alternative for similar problems that can sometimes be better than short Thread.Sleep invocations.
Also see this question: What's the purpose of Thread.SpinWait method?
这里有很多“高级”答案,但 IMO 只需使用 Thread.Sleep(lowvalue) 就足以满足大多数人的需求。
计时器也是一种解决方案,但计时器背后的代码也是一个无限循环 - 我认为 - 在经过的时间间隔内触发您的代码,但它们具有正确的无限循环设置。
如果您需要大睡眠,可以将其切成小睡眠。
因此,对于非 UI 应用程序来说,这样的解决方案是一个简单易用的 0% CPU 解决方案。
关于操作系统如何检测应用程序是否无响应。除了 UI 应用程序之外,我不知道还有其他测试,其中有方法可以检查 UI 线程是否处理 UI 代码。休眠在 UI 上的线程很容易被发现。 Windows“应用程序无响应”使用简单的本机方法“SendMessageTimeout”来检测应用程序是否有无响应的 UI。
UI 应用程序上的任何无限循环都应始终在单独的线程中运行。
Lots of "advanced" answers here but IMO simply using a Thread.Sleep(lowvalue) should suffice for most.
Timers are also a solution, but the code behind a timer is also an infinity loop - I would assume - that fires your code on elapsed intervals, but they have the correct infinity-loop setup.
If you need a large sleep, you can cut it into smaller sleeps.
So something like this is a simple and easy 0% CPU solution for a non-UI app.
Regarding how the OS detects if the app is unresponsive. I do not know of any other tests than on UI applications, where there are methods to check if the UI thread processes UI code. Thread sleeps on the UI will easily be discovered. The Windows "Application is unresponsive" uses a simple native method "SendMessageTimeout" to see detect if the app has an unresponse UI.
Any infinity loop on an UI app should always be run in a separate thread.
要保持控制台应用程序运行,只需将
Console.ReadLine()
添加到Main()
中代码的末尾即可。如果用户无法终止应用程序,您可以使用如下循环来执行此操作:
To keep console applications running just add a
Console.ReadLine()
to the end of your code inMain()
.If the user shouldn't be able to terminate the application you can do this with a loop like the following: