如何在两个窗口中完成的WPF GUI主线程上提高性能

时间:2019-06-12 07:07:05

标签: c# wpf performance task

我有一个wpf应用程序,它有mainWindow,可以创建显示在辅助监视器上的_otherWindow。两个窗口的元素都需要随时间变化。 (mainWindow更新了Image以及plots图,最后_otherWindow根据某些计算更新了shape的位置)。

我的问题是什么?好吧,我正在Thread内逐帧阅读视频(不过,我想允许使用相机拍摄的视频流允许这样做)。当我在特定时间内每帧更新GUI时,应用程序负担越来越重,运行速度越来越慢...

我意识到注释mainWindow updating Image或注释_otherWindow updating shape position代码会使应用程序正常运行,但问题在于它们一起运行时。

这是详细说明

首先,我计算_otherWindow内的一些内容并计算shape的位置。 然后,我计算一些与image相关的内容,然后update framebitmap添加一些内容 然后,我更新_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();

1 个答案:

答案 0 :(得分:1)

很难猜测。你有Visual Studio吗?我认为,甚至社区版也具有某些性能分析功能(菜单:分析/性能分析器...)。这可能指出了一些不太明显的瓶颈。

我的想法:

  1. getBitmapFromHeavyComputationMethod2似乎每次都会返回一个新的位图。我无法推断出它返回的实际类型,但可能涉及半大的非托管内存分配并实现了IDisposable。您可能会检查是否处理得当。

  2. 您可以使用WriteableBitmap而不是为每个帧创建一个新的位图吗?如果这样做,请确保将其锁定和解锁。如果需要,也许可以在两个位图之间进行乒乓切换。

  3. 似乎您可能正在使用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} }可以。