我有一个VB.Net和WPF应用程序。该应用程序的一部分使用“图像生成器”来计算图像。另一个是使用“计时器”来显示直方图。当使用生成器每秒创建大约2帧时,CPU使用率约为零,图像创建正常,直方图将在Timer中创建1秒钟。一切似乎都很完美。
如果我让我自己的“图像生成器”使用大约20 FPS而不是2来计算图像,则CPU最高可达20%,但Timer不会抛出事件。 GUI中的图像显示20FPS。如果我停止图像生成器,Timer会立即触发他的事件。
我不知道从哪里开始搜索。
Me.TimerCalc = New System.Windows.Threading.DispatcherTimer
Me.TimerCalc.Interval = TimeSpan.FromMilliseconds(1000)
Me.TimerCalc.Start
Private Sub TimerCalc_Tick(sender As Object, e As System.EventArgs) Handles TimerCalc.Tick
'Does not fire if other process is running by using more CPU
End Sub
如果我将帧速率降低到大约10FPS,有时DispatcherTimer会抛出他的事件,有时则不会。如果我增加帧速率,DispatcherTimer将抛出更少的事件。
修改 在此下载演示项目:VisualStudio 2010 Dispatcher Test with Windows Form Timer
修改 上传的演示视频:Video where cube does not rotate anymore
答案 0 :(得分:3)
我无法在我的问题上复制这个问题。它对我来说很好。
我确实想知道你在TimerCalc_Tick函数中可能会做些什么。你在那里做的任何事都会阻止Dispatcher。在完成该事件之前,该事件不会再次触发。所以我绝对可以看到搞砸了。
在查看代码之后,观看视频,并在我的机器上播放它,我认为当你达到更高的费率时,你只是让Dispatcher挨饿。我不确定为什么矩形完全停止为你旋转(它不适合我),但如果你的处理器/显卡低于我的,我可以看出这是不同的。当我像你在视频中一样向左运行滑块时,我的处理器(所有四个核心)都固定在40%左右。低端机器会比这更差,可能会让其他线程挨饿。
如果您按照上面发布的项目进行,只需进行一次更改,请转到此处:
Public Sub New()
Me.TimerRefresh = New System.Windows.Forms.Timer
Me.TimerRefresh.Interval = Me.Intervall
Me.TimerRefresh.Enabled = True
End Sub
进入这个:
Public Sub New()
Me.TimerRefresh = New System.Windows.Forms.Timer
Me.TimerRefresh.Interval = Me.Intervall
Me.TimerRefresh.Enabled = False
End Sub
这样你就不会实际启动进行所有处理的计时器,然后运行应用程序并一直向左运行滑块,矩形是否仍然停止?如果没有,那么我相信你只是让调度员挨饿。如果它......那我仍然感到困惑。
答案 1 :(得分:0)
如果您想要短而稳定的间隔,请使用多媒体计时器(在代码项目网站上找到点网络包装器)。
如果您需要在UI的线程上工作,请在多媒体计时器的事件上调用调度程序(而不是调度程序计时器)。将调度程序优先级设置为输入以确保UI不会阻止它。 确保操作比间隔少得多。
建议使用5毫秒及以上的间隔时间。
答案 2 :(得分:0)
更新图像时会阻止Dispatcher。使用新线程取消阻止。
Private Sub cImageGenerator_NewImageAvailable() Handles cImageGenerator.NewImageAvailable
If _IsReady = False Then Exit Sub
_IsReady = False
' ################
' # Thread - Christian Zech
' #################
Dim trd As New System.Threading.Thread(Sub()
' ##########################
' # Clone
' ##########################
Dim bm As System.Drawing.Bitmap = Me.cImageGenerator.CreateBitmap '.Clone
Dim imgSrc As ImageSource = BitmapToWpfBitmapSource(bm)
imgSrc.Freeze() 'needed because otherwise we will get the error: The calling thread cannot access this object because a different thread owns it.
Me.Dispatcher.Invoke(New Action(Of ImageSource)(AddressOf UpdateImage), imgSrc)
End Sub)
trd.SetApartmentState(System.Threading.ApartmentState.STA) ''ToDo: MTA probieren
trd.Name = "cImageGenerator_NewImageAvailable"
trd.Start()
End Sub
Private Sub UpdateImage(ByVal img As ImageSource)
Me.img1.Source = img
_IsReady = True
End Sub