递归搜索任务中的文件会冻结 Mono 上的表单

Recursively searching for file in task freezes form on Mono

我正在 VB.Net 中开发一个文件浏览器,它将在 Mono 框架的 Ubuntu 上 运行。在我决定实现搜索功能之前,一切都很顺利。我已将其设置为在新任务中搜索 运行s,并且用户可以从表单中取消它。这在 Windows 上工作正常,但是当 运行 在 Mono 上时,我得到奇怪的结果:

我试过在整个过程中插入 'Application.DoEvents()',但这没有帮助。我什至尝试 运行 在没有任务的情况下在 UI 线程上使用代码,但这显然只会导致所有内容冻结。

代码如下:

通过文本框调用 Search() 方法,调用时显示取消按钮,如果单击则调用 tokenSource2.Cancel()

Dim tokenSource2 As New CancellationTokenSource()
Dim ct As CancellationToken = tokenSource2.Token

Private Sub Search(ByVal txt As String, ByVal dir As String)
    CancelSearch()
    tokenSource2 = New CancellationTokenSource()
    ct = tokenSource2.Token
    pnl_cancelsearch.Show()
    Dim t As Task = Task.Factory.StartNew(Sub()
                                              If ct.IsCancellationRequested Then
                                                  Exit Sub
                                              End If
                                              ListView1.Clear()
                                              Dim iscasesensitive As Boolean = ConfigManager.SearchIsCaseSensitive
                                              If Not searchhistory.Contains(txt) Then
                                                  searchhistory.Add(txt)
                                                  combo_search.Items.Add(txt)
                                              End If
                                              If ct.IsCancellationRequested Then
                                                  Exit Sub
                                              End If
                                              If dir = "" Then
                                                  For Each item As String In Directory.GetLogicalDrives
                                                      If ct.IsCancellationRequested Then
                                                          Exit Sub
                                                      End If
                                                      SearchRec(txt, item, iscasesensitive)
                                                  Next
                                              Else
                                                  SearchRec(txt, dir)
                                              End If
                                              pnl_cancelsearch.Hide()
                                          End Sub)
End Sub

Private Sub SearchRec(ByVal txt As String, ByVal rootdir As String, Optional ByVal casesensitive As Boolean = True)
    For Each item As String In Directory.GetFiles(rootdir)
        If ct.IsCancellationRequested Then
            Exit Sub
        End If
        If casesensitive Then
            If item.Contains(txt) Then
                AddItem(item)
            End If
        Else
            If item.ToLower.Contains(txt.ToLower) Then
                AddItem(item)
            End If
        End If
    Next
    For Each item As String In Directory.GetDirectories(rootdir)
        If ct.IsCancellationRequested Then
            Exit Sub
        End If
        SearchRec(txt, item)
    Next
End Sub

我该如何解决这个问题?我究竟做错了什么?它在 Windows 上运行良好,但在 Mono 上运行不佳。

你遇到了一个问题:你正在修改 UI 并且你希望你的任务作为一个新线程执行(因为你没有使用 await 所以如果正在执行则没有共享时间在主线程上)。

如果您强制任务创建一个新线程(为此您必须明确设置 TaskScheduler.Default 作为使用的任务调度程序),那么 UI 代码将导致跨线程异常。而且,如果您不强制任务在新线程上 运行 ,那么它将在阻塞它的主线程上执行。

Mono Forms 的实现至少很差,所以它比 Windows 慢很多,它可以完美地在 Windows 上你不会注意到缓慢,因为它足够快并且在另一个使用 Mono 的 OS 上速度较慢,您注意到 UI 更新。

首先,如果可以的话,避免在 Mono 上使用 Forms,使用 GTK# 或其他 UI 工具包。

此外,将 UI 逻辑与数据逻辑分开,创建一个检索所有数据的任务(使用任务或线程池),并在获取数据后更新 UI ,我敢打赌你仍然会发现它很慢,因为 UI 更新。

感谢另一位用户,解决方案是在更新 UI 时使用 BeginInvoke,效果很好。