递归搜索任务中的文件会冻结 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,效果很好。
我正在 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,效果很好。