如何在不使用大量CPU的情况下连续循环

时间:2015-01-19 16:47:13

标签: vb.net loops cpu-usage

我有一个应用程序,它运行一个任务来检查目录中的文件,并在文件添加到目录时完成。这是一个简化的例子:

Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim addedFile = Await Task.Factory.StartNew(New Func(Of FileInfo)(
        Function()
            Dim di = New DirectoryInfo("C:\_Temporary\Test")

            Do While True
                Dim files = di.GetFiles()

                If (files.Count > 0) Then
                    Return files(0)
                End If
            Loop
        End Function))

    MsgBox(addedFile.FullName)
End Sub

我遗漏了诸如取消令牌等多余的细节。

问题是代码运行时CPU保持稳定在12%左右。即使我在while循环中注释掉了主体,它仍然是相同的。

如何创建循环机制,这是等待文件到达目录的非等待操作所必需的,而不使用那么多的CPU?

注意:问题不在于涉及文件系统的具体案例;它通常会循环非等待的操作以及对CPU的影响。

相比之下,Windows事件消息循环占用不到1% - 例如如果我在点击运行上述代码的“Button1”之前查看我的应用程序的CPU使用情况。

3 个答案:

答案 0 :(得分:3)

使用Filewatcher类在目录更改时接收事件: http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher%28v=vs.110%29.aspx

' Create a new FileSystemWatcher and set its properties. 
Dim watcher As New FileSystemWatcher()
watcher.Path = "C:\_Temporary\Test"
' Watch for changes in LastAccess and LastWrite times, and 
' the renaming of files or directories. 
watcher.NotifyFilter = (NotifyFilters.LastAccess Or NotifyFilters.LastWrite Or NotifyFilters.FileName Or NotifyFilters.DirectoryName)
' Only watch text files.
watcher.Filter = "*.txt" 

' Add event handlers. 
AddHandler watcher.Created, AddressOf OnChanged

' Define the event handlers. 
Private Shared Sub OnChanged(source As Object, e As FileSystemEventArgs)
   ' Specify what is done when a file is changed, created, or deleted.
   MsgBox(e.FullPath)
End Sub     

答案 1 :(得分:0)

因此,最好每秒检查一次文件(但不使用While True循环,总是避免使用它们。)

Dim timerDelegate As TimerCallback = AddressOf RepeatingFunction
Dim autoEvent As New AutoResetEvent(True)
Dim dt As New System.Threading.Timer(timerDelegate, autoEvent, 0, 1000)

MSDN:http://msdn.microsoft.com/it-it/library/system.threading.timer%28v=vs.110%29.aspx

注意:RepeatingFunction必须得到充实。 Threading.Timer构造函数的最后一个参数也代表了ticks之间的间隔。

答案 2 :(得分:0)

您正在投票。出于多种原因,轮询绝不是一个好主意。轮询在软件中非常普遍,即使在一些众所周知的商业软件中仍然无名。如您所知,这会导致许多问题不必要地占用处理器,以防止处理器休眠并导致电池耗电更快。

解决方案#1:最理想的解决方案是找到其他人指出的内置观察器。在幕后,观察者可能正在使用特定的中断机制或使用内核定时例程来模拟中断。

解决方案#2:如果不存在这样的观察者,你可以使用带有sleep()的for / while循环来检查每隔这么多秒:它检查,进入休眠状态一段时间,然后再次检查。 sleep()函数不会使用任何处理时间(不是完全正确但实际上是这样)。

即使使用解决方案#2,您也可能陷入一些陷阱,导致您使用比您需要的更多处理。对您需要检查病情的频率进行实际分析。一个非常常见的错误是在错误的假设下设置一个非常短的轮询周期,即您的应用程序将更快地做出反应。

如果您的典型事件每分钟或每两分钟发生一次,并且您需要在5秒内对事件做出反应,那么轮询时间为10毫秒并不会获得任何收益并且会伤害每个人的表现。在这种情况下,您可以每2秒进行一次轮询,比10 ms更频繁地减少三个数量级。

许多人都没有意识到的另一件事是,在典型的操作系统(例如Linux和Windows)中,定时器等的基本分辨率大约为10毫秒,即使数据结构允许您指定可能的微秒。