递归文件夹搜索在代码执行期间获取 'not responding'
Recursive folder search gets during code execution 'not responding'
我有一个按钮、一个文本框和一个列表视图。我尝试的只是递归循环遍历我的文件系统。例如,C:\Windows。当然,应用程序需要遍历十万个目录,这需要 CPU 和 RAM 性能。
但问题是,我的应用程序 window 在此期间进入 'not responding' 状态。
我可以通过优化我的代码来避免这种行为吗?
我的VB.NET代码:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim rootDir As String = String.Empty
Dim di As DirectoryInfo
rootDir = TextBox1.Text.Trim()
di = New DirectoryInfo(rootDir)
' start recursively loop trough filesystem
recur_getdirectories(di, 0)
End Sub
Public Sub recur_getdirectories(ByVal di As DirectoryInfo, ByRef int As Integer)
int = int + 1
Try
For Each directory As DirectoryInfo In di.GetDirectories()
ListView1.Items.Add(directory.FullName)
Label1.Text = int
recur_getdirectories(directory, int)
Next
Catch ex As UnauthorizedAccessException
End Try
End Sub
我可以通过优化我的代码来避免这种行为吗? - 好的第一步是了解为什么“不响应”的发生以及 windows 的工作原理。
当您启动 windows 表单程序时,会建立一个队列,并有一个线程专用于处理队列中的所有消息。如果用户点击某些东西,按键等,然后消息被发布到队列中并且线程开始处理它们。如果 windows 注意到队列越来越长,消息不再被处理,它会将 window 标记为“未响应”。
当正在处理一条消息(单击按钮)时,通常是消耗队列的线程在代码的 X_Click 按钮事件处理程序中启动。如果您以这样的方式编写代码,该线程将花费几秒钟(或 minutes/hours.. 甚至更长)来完成您的代码并返回到它正在做的事情(处理队列),那么您将肯定会导致无响应 window
这就是你所做的;枚举硬盘上的所有目录需要很长时间。当线程执行此操作时,它不会处理任何 window 消息 - 不会处理任何点击,不会发生 UI 更新,如果您尝试与 [=40] 进行交互,则会出现“无响应” =] 因为 windows 会注意到您发出的消息没有被使用
你需要使用一种机制,让线程回到它之前正在做的事情,并且鉴于没有 async/await 路由可供你使用,我很想去jdigital 建议使用 backgroundworker,因为它使事情变得更容易,只要您使用进度报告机制来触发更新即可。这是因为 worker 在后台线程上执行工作,但是 windows 控件只能由创建它们的线程访问。 Backgroundworker 将为您管理;简而言之——永远不要从 DoWork
中访问 windows 控件
Private X_Click() Handles X.Xlixk()
_bgw.RunWorkerAsync(TextBox1.Text.Trim()) 'pass the start directory in as an argument
End Sub
Private Sub Bgw_DoWork(sender As Object, e As DoWorkEventArgs) Handles _bgw.DoWork
Dim rootDir As String = String.Empty
Dim di As DirectoryInfo
rootDir = e.Argument.ToString()
di = New DirectoryInfo(rootDir)
' start recursively loop trough filesystem
Recur_GetDirectories(di)
End Sub
Public Sub Recur_GetDirectories(ByVal di As DirectoryInfo)
Try
For Each directory As DirectoryInfo In di.GetDirectories()
_bgw.ReportProgress(0, directory.FullName) 'pass the directory path in the progress report. Do NOT access windows controls from inside DoWork; it does not run on the windowing thread
Recur_GetDirectories(directory)
Next
Catch ex As UnauthorizedAccessException
End Try
End Sub
Private Sub Bgw_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles _bgw.ProgressChanged
ListView1.Items.Add(e.UserState.ToString()) ' only access windows controls in the ProgressChanged event; it runs on the window thread
End Sub
接下来您可能会注意到,您将向列表视图中发布数以万计的项目,并且它可能会花费 巨大 的金额时间重绘自己。输入 Jimi 关于如何将大量内容加载到 windows 控件中而不会对性能造成太大影响的建议(即,如果您将 100 个项目加载到控件中并且它自己重绘 100 次,您可以通过转动来获得更好的性能关闭临时更新,因此它不会花费大量时间无休止地重绘自己只是在不久之后失效并需要再次重绘)
我有一个按钮、一个文本框和一个列表视图。我尝试的只是递归循环遍历我的文件系统。例如,C:\Windows。当然,应用程序需要遍历十万个目录,这需要 CPU 和 RAM 性能。 但问题是,我的应用程序 window 在此期间进入 'not responding' 状态。
我可以通过优化我的代码来避免这种行为吗?
我的VB.NET代码:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim rootDir As String = String.Empty
Dim di As DirectoryInfo
rootDir = TextBox1.Text.Trim()
di = New DirectoryInfo(rootDir)
' start recursively loop trough filesystem
recur_getdirectories(di, 0)
End Sub
Public Sub recur_getdirectories(ByVal di As DirectoryInfo, ByRef int As Integer)
int = int + 1
Try
For Each directory As DirectoryInfo In di.GetDirectories()
ListView1.Items.Add(directory.FullName)
Label1.Text = int
recur_getdirectories(directory, int)
Next
Catch ex As UnauthorizedAccessException
End Try
End Sub
我可以通过优化我的代码来避免这种行为吗? - 好的第一步是了解为什么“不响应”的发生以及 windows 的工作原理。
当您启动 windows 表单程序时,会建立一个队列,并有一个线程专用于处理队列中的所有消息。如果用户点击某些东西,按键等,然后消息被发布到队列中并且线程开始处理它们。如果 windows 注意到队列越来越长,消息不再被处理,它会将 window 标记为“未响应”。
当正在处理一条消息(单击按钮)时,通常是消耗队列的线程在代码的 X_Click 按钮事件处理程序中启动。如果您以这样的方式编写代码,该线程将花费几秒钟(或 minutes/hours.. 甚至更长)来完成您的代码并返回到它正在做的事情(处理队列),那么您将肯定会导致无响应 window
这就是你所做的;枚举硬盘上的所有目录需要很长时间。当线程执行此操作时,它不会处理任何 window 消息 - 不会处理任何点击,不会发生 UI 更新,如果您尝试与 [=40] 进行交互,则会出现“无响应” =] 因为 windows 会注意到您发出的消息没有被使用
你需要使用一种机制,让线程回到它之前正在做的事情,并且鉴于没有 async/await 路由可供你使用,我很想去jdigital 建议使用 backgroundworker,因为它使事情变得更容易,只要您使用进度报告机制来触发更新即可。这是因为 worker 在后台线程上执行工作,但是 windows 控件只能由创建它们的线程访问。 Backgroundworker 将为您管理;简而言之——永远不要从 DoWork
中访问 windows 控件
Private X_Click() Handles X.Xlixk()
_bgw.RunWorkerAsync(TextBox1.Text.Trim()) 'pass the start directory in as an argument
End Sub
Private Sub Bgw_DoWork(sender As Object, e As DoWorkEventArgs) Handles _bgw.DoWork
Dim rootDir As String = String.Empty
Dim di As DirectoryInfo
rootDir = e.Argument.ToString()
di = New DirectoryInfo(rootDir)
' start recursively loop trough filesystem
Recur_GetDirectories(di)
End Sub
Public Sub Recur_GetDirectories(ByVal di As DirectoryInfo)
Try
For Each directory As DirectoryInfo In di.GetDirectories()
_bgw.ReportProgress(0, directory.FullName) 'pass the directory path in the progress report. Do NOT access windows controls from inside DoWork; it does not run on the windowing thread
Recur_GetDirectories(directory)
Next
Catch ex As UnauthorizedAccessException
End Try
End Sub
Private Sub Bgw_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles _bgw.ProgressChanged
ListView1.Items.Add(e.UserState.ToString()) ' only access windows controls in the ProgressChanged event; it runs on the window thread
End Sub
接下来您可能会注意到,您将向列表视图中发布数以万计的项目,并且它可能会花费 巨大 的金额时间重绘自己。输入 Jimi 关于如何将大量内容加载到 windows 控件中而不会对性能造成太大影响的建议(即,如果您将 100 个项目加载到控件中并且它自己重绘 100 次,您可以通过转动来获得更好的性能关闭临时更新,因此它不会花费大量时间无休止地重绘自己只是在不久之后失效并需要再次重绘)