c# - 如何提高在两个窗口中完成的 wpf GUI 主线程的性能
问题描述
我有一个 wpf 应用程序,它mainWindow
可以创建_otherWindow
在辅助监视器上显示的内容。两个窗口都有需要随时间变化的元素。(mainWindow
更新一个Image
和plots
一个图,最后根据一些计算_otherWindow
更新一个位置)。shape
我的问题是什么?好吧,我正在 a中逐帧读取视频Thread
(但是我想允许使用相机拍摄的流)。当我在特定时间内每帧更新 GUI 时,应用程序的负载越来越大,而且速度越来越慢......
我意识到注释mainWindow updating Image
或者注释_otherWindow
updating shape position
代码可以使应用程序运行良好,但问题是它们何时一起运行。
这里有详细的说明
首先,我计算内部的一些东西_otherWindow
并计算 a 的位置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();
解决方案
有点难以猜测。你有 Visual Studio 吗?我认为即使是社区版也有一些分析功能(菜单:Analyze/Performance Profiler...)。这可能会指出一些不明显的瓶颈。
我的想法:
getBitmapFromHeavyComputationMethod2
似乎每次都返回一个新的位图。我无法推断它返回的实际类型,但它可能涉及半大型非托管内存分配和实现IDisposable
。您可能会检查您是否适当地处理了它。您可以使用WriteableBitmap ,而不是为每一帧创建一个新的位图吗?如果您这样做,请务必锁定和解锁它。如果需要,也许可以在两个位图之间进行 ping-pong(交替)。
看来您可能正在使用您的 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次——也许您的方法可以接受。Read
推荐阅读
- c# - 如何在提交操作时编辑 MS Bot Framework 自适应卡
- javascript - 结合两个传单扩展?
- apache - 将支付信息发送到服务器的最佳方式是什么?
- python - 将两个立体图像传递给 Keras 中的损失函数的最干净和最有效的方法是什么?
- sql - 如何在具有分隔类别列表的列上编写查询
- process - 为什么我的自动化 Blue Prism 进程在调度程序模式下的某些阶段会失败,而这些步骤在调试模式下完全可以正常工作?
- java - 将数据从 MySQL 加载到 JSP 页面中,无需表单
- javascript - 如何实现在内部范围内缓存/记忆请求结果的功能
- c++ - 为什么我的递归函数按降序打印,然后按升序打印?
- javascript - 取消去抖功能