gpt4 book ai didi

.net - 可靠地更新 winforms 应用程序中的 UI 线程

转载 作者:行者123 更新时间:2023-12-03 13:04:00 25 4
gpt4 key购买 nike

我有一个长时间运行的机器学习程序,我在 winforms 应用程序中使用所有内核并行运行。我会定期更新 UI 以报告进度。

机器似乎选择相当随机的时间在 UI 线程上执行消息泵。有时我几分钟都没有收到更新,有时我每次发送消息都会收到一条消息。

我已经尝试了各种方法来使它可靠,包括从后台线程进行标准调用,使用来自后台工作人员的进度报告,在 UI 线程上使用计时器来收集信息并显示它,减少最大线程数可以并行运行,扰乱线程优先级等。我发现可靠地获得更新的唯一方法是向 winforms 程序添加一个控制台并将进度输出到控制台。出于某种原因,这是 100% 可靠的,但它是一个真正的 hack,看起来很乱。

有谁知道强制 ui 线程可靠更新的方法吗?

根据要求:这是复制错误的最基本代码。创建一个带有名为 label1 的标签的表单。该代码尝试每百万次迭代更新一次标签。

Module testmodule
delegate sub invokedelegate(txt as string)

Sub long_running_process()
Dim x(100000000) As Integer
Dim cnt As Integer
Dim syncobject As New Object

form1.Label1.Text = "started"

Parallel.ForEach(x, Sub(z)

'*** This just put in to make the processors do some work.
Dim p As New Random
Dim m As Double = p.NextDouble
Dim zzz As Double = Math.Cosh(m) + Math.Cos(m)

'*** This is the basic updating method.
SyncLock syncobject
cnt += 1

'*** Update every millionth iteration
If cnt Mod 1000000 < 1 Then

'**** This is how it is marshalled to the UI thead.
If Form1.InvokeRequired Then
Form1.BeginInvoke(New invokedelegate(AddressOf invokemethod), {cnt})
Else
Form1.Label1.Text = cnt
End If

End If
End SyncLock
End Sub)

Form1.Label1.Text = "Finished"
End Sub
Sub invokemethod(txt As String)
form1.Label1.Text = txt
End Sub
end module

最佳答案

问题是 Parallel.ForEach 坚持在 UI 线程上运行所有任务。我对此进行更改的一种方法是从 BackgroundWorker.DoWork 调用 long_running_process,如下所示:

Public Class Form1

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
BackgroundWorker1.RunWorkerAsync()

End Sub

Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
testmodule.long_running_process(Label1)
End Sub
End Class

请注意,我必须提供 Label1 作为参数,否则 InvokeRequired 总是返回 false。

更改后的 long_running_process 如下所示:

Sub long_running_process(lbl As Label)
Dim x(100000000) As Integer
Dim cnt As Integer
Dim syncobject As New Object

If lbl.InvokeRequired Then
lbl.BeginInvoke(New MethodInvoker(Sub()
lbl.Text = "started"
End Sub), Nothing)
End If


Parallel.ForEach(x, Sub(z)

'*** This just put in to make the processors do some work.
Dim p As New Random
Dim m As Double = p.NextDouble
Dim zzz As Double = Math.Cosh(m) + Math.Cos(m)

'*** This is the basic updating method.
SyncLock syncobject
cnt += 1

'*** Update every millionth iteration
If cnt Mod 1000000 < 1 Then

'**** This is how it is marshalled to the UI thead.
If lbl.InvokeRequired Then
lbl.BeginInvoke(New invokedelegate(AddressOf invokemethod), {cnt.ToString()})
Else
lbl.Text = cnt
End If

End If
End SyncLock
End Sub)

If lbl.InvokeRequired Then
lbl.BeginInvoke(New MethodInvoker(Sub()
lbl.Text = "Finished"
End Sub), Nothing)
End If

End Sub
Sub invokemethod(txt As String)
Form1.Label1.Text = txt
End Sub

计数器随着这些变化顺利更新。

关于.net - 可靠地更新 winforms 应用程序中的 UI 线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37879570/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com