You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VB.NET中While循环处理任务列表时UI冻结问题的解决方法

解决文件夹处理时UI冻结的问题

问题分析

你的代码在批量获取文件夹信息时出现UI冻结,核心原因有两点:

  • 冗余的Task.Run嵌套:GetFolderInfo本身是异步函数,内部又用Task.Run包裹异步操作,导致不必要的线程切换和资源消耗。
  • Task.WhenAny循环的低效操作:每次调用processQuery.Remove(finishedTask)是O(n)复杂度,当文件夹数量较多时,会占用UI线程的处理时间。

另外,GetDirectorySize里的Directory.GetFiles是同步阻塞API,遍历大量文件时会长时间占用线程,间接影响UI响应。

优化方案

1. 移除冗余的Task.Run嵌套

修改GetFolderInfo函数,去掉外层的Task.Run,同时并行执行内部的异步任务提升效率:

Async Function GetFolderInfo(folder As String, ct As CancellationToken) As Task(Of String())
    ct.ThrowIfCancellationRequested()
    Dim folder_info = New DirectoryInfo(folder)
    ' 并行执行两个异步任务,减少总耗时
    Dim md5Task = GetFileMd5(folder, False, ct)
    Dim sizeTask = GetDirectorySize(folder, ct)
    Await Task.WhenAll(md5Task, sizeTask)
    
    Return {folder_info.Name, Await md5Task, Await sizeTask}
End Function

2. 替换低效的Task.WhenAny循环

用更简洁高效的遍历方式替代原循环,避免List.Remove的性能开销:

Async Function ProcessFolders(ct As CancellationToken, FolderList As IEnumerable(Of String)) As Task
    ' 创建任务集合并传入取消令牌
    Dim tasks = FolderList.Select(Async folder =>
    {
        ct.ThrowIfCancellationRequested()
        Return Await GetFolderInfo(folder, ct)
    }).ToList()
    
    ' 逐个处理任务结果,Await会自动回到UI上下文执行更新
    For Each task In tasks
        ct.ThrowIfCancellationRequested()
        Dim result = Await task
        folder_dt.Rows.Add(Nothing, result(0), result(1), result(2))
        ' WinForms环境下可选:强制UI刷新,避免更新堆积
        ' Application.DoEvents()
    Next
End Function

3. 优化文件操作的阻塞问题

将GetDirectorySize中的Directory.GetFiles替换为Directory.EnumerateFiles,减少内存占用;同时添加取消令牌检查,支持中途终止操作:

Shared Async Function GetDirectorySize(path As String, ct As CancellationToken) As Task(Of Long)
    Return Await Task.Run(Function()
                              ct.ThrowIfCancellationRequested()
                              Dim totalSize As Long = 0
                              For Each file In Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories)
                                  ct.ThrowIfCancellationRequested()
                                  totalSize += New FileInfo(file).Length
                              Next
                              Return totalSize
                          End Function)
End Function

4. 完善取消令牌的使用

在所有耗时操作中添加取消令牌检查,确保用户触发取消时任务能及时终止:

Private Async Function GetFileMd5(file_name As String, convert_file As Boolean, ct As CancellationToken) As Task(Of String)
    Return Await Task.Run(Function()
                              ct.ThrowIfCancellationRequested()
                              Dim byteHash() As Byte

                              Dim ByteArrayToString = Function(arrInput() As Byte)
                                                          Dim sb As New Text.StringBuilder(arrInput.Length * 2)
                                                          For i As Integer = 0 To arrInput.Length - 1
                                                              sb.Append(arrInput(i).ToString("X2"))
                                                          Next
                                                          Return sb.ToString().ToLower
                                                      End Function

                              If convert_file Then
                                  ct.ThrowIfCancellationRequested()
                                  Using stream = File.OpenRead(file_name)
                                      byteHash = Md5CSP.ComputeHash(stream)
                                  End Using
                                  Return ByteArrayToString(byteHash)
                              End If

                              ct.ThrowIfCancellationRequested()
                              byteHash = Md5CSP.ComputeHash(System.Text.Encoding.Unicode.GetBytes(file_name))
                              Return ByteArrayToString(byteHash)
                          End Function)
End Function

内容的提问来源于stack exchange,提问作者Dan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 23:50:14