我有一个wpf应用程序,它有mainWindow
,可以创建显示在辅助监视器上的_otherWindow
。两个窗口的元素都需要随时间变化。 (mainWindow
更新了Image
以及plots
图,最后_otherWindow
根据某些计算更新了shape
的位置)。
我的问题是什么?好吧,我正在Thread
内逐帧阅读视频(不过,我想允许使用相机拍摄的视频流允许这样做)。当我在特定时间内每帧更新GUI时,应用程序负担越来越重,运行速度越来越慢...
我意识到注释mainWindow updating Image
或注释_otherWindow
updating shape position
代码会使应用程序正常运行,但问题在于它们一起运行时。
这是详细说明
首先,我计算_otherWindow
内的一些内容并计算shape
的位置。
然后,我计算一些与image
相关的内容,然后update frame
向bitmap
添加一些内容
然后,我更新_otherWindow
内部形状的位置
最后,我绘制结果(该绘制需要从mainWindow
和_otherWindow
获得的数据)
为此,我使用任务并等待它们。
我有这个:
private Thread _camera;
private void CaptureVideo()
{
_camera = new Thread(CaptureVideoCallback)
{
Priority = ThreadPriority.Highest
};
_camera.Start();
}
private VideoCapture _capture;
private void CaptureVideoCallback()
{
//some computing here read from a video file...
_capture = new VideoCapture("someVideo.mp4");
for (var i = 0; i < _capture.FrameCount; i++)
{
_capture.Read(_frame);
if (_frame.Empty()) return;
//*************task that does heavy computation in other class
var heavyTaskOutput1 = Task.Factory.StartNew(() =>
{
_otherWindow.Dispatcher.Invoke(() =>
{
ResultFromHeavyComputationMethod1 = _otherWindow.HeavyComputationMethod1();
});
}
);
////*************task that does heavy computation in current class
var heavyTaskOutput2 = Task.Factory.StartNew(() =>
{
ResultFromHeavyComputationMethod2 = HeavyComputationMethod2(ref _frame);
var bitmap = getBitmapFromHeavyComputationMethod2();
bitmap.Freeze();
//update GUI in main thread
Dispatcher.CurrentDispatcher.Invoke(() => ImageSource = bitmap);
});
////*************wait both task to complete
Task.WaitAll(heavyTaskOutput1, heavyTaskOutput2 );
//update _otherWindow GUI
var outputGui = Task.Factory.StartNew(() =>
{
_otherWindow.Dispatcher.Invoke(() =>
{
_otherWindow.UpdateGui();
});
}
);
outputGui.Wait();
////*************plot in a char using gotten results, UPDATE GUI
Task.Run(() =>
{
PlotHorizontal();
});
}
}
什么是加快此速度的好方法? 我的意思是我知道GUI东西需要在主线程上完成,但这会使事情变慢。
更改了Clemens建议的代码:
//*************task that does heavy computation in other class
var heavyTaskOutput1 = Task.Run(() =>
{
ResultFromHeavyComputationMethod1 = _otherWindow.HeavyComputationMethod1();
}
);
////*************task that does heavy computation in current class
var heavyTaskOutput2 = Task.Run(() =>
{
ResultFromHeavyComputationMethod2 = HeavyComputationMethod2(ref _frame);
var bitmap = getBitmapFromHeavyComputationMethod2();
bitmap.Freeze();
//update GUI in main thread
Dispatcher.CurrentDispatcher.Invoke(() => ImageSource = bitmap);
});
////*************wait both task to complete
Task.WaitAll(heavyTaskOutput1, heavyTaskOutput2);
//update _otherWindow GUI
var outputGui = Task.Run(() =>
{
_otherWindow.Dispatcher.Invoke(() =>
{
_otherWindow.UpdateGui();
});
}
);
outputGui.Wait();
答案 0 :(得分:1)
很难猜测。你有Visual Studio吗?我认为,甚至社区版也具有某些性能分析功能(菜单:分析/性能分析器...)。这可能指出了一些不太明显的瓶颈。
我的想法:
getBitmapFromHeavyComputationMethod2
似乎每次都会返回一个新的位图。我无法推断出它返回的实际类型,但可能涉及半大的非托管内存分配并实现了IDisposable
。您可能会检查是否处理得当。
您可以使用WriteableBitmap而不是为每个帧创建一个新的位图吗?如果这样做,请确保将其锁定和解锁。如果需要,也许可以在两个位图之间进行乒乓切换。
似乎您可能正在使用I / O读取(第一个,然后另一个)序列化“大量计算”。也许也以async
的形式启动读取,然后在WaitAll
中等待读取,以便计算和I / O可以同时发生。这种形状的东西:
var readResult = _capture.Read(_frame);
for (...) {
// check read result
// ...
// launch heavy computation
readResult = Task.Run(() => _capture.Read(nextFrame);
Task.WaitAll(pupilOutput, outputTest, readResult);
_frame = nextFrame;
}
请注意,对于 N 帧,这将读取 N + 1 次-也许是您的{{1} }可以。