首页 > 解决方案 > 在英特尔 NUC NUC7CJYH 上使用 ~100% CPU 使用率的 WPF QR 解码应用程序的优化

问题描述

我一直在研究一个 WPF,它解码用户持有网络摄像头的 QR 码。该应用程序运行良好,在我的开发机器上运行良好(Core i7 3770 CPU,NVidia Quadro K4200 GPU 上最多 23% 的 CPU 和 4% 的 GPU 使用率)但是当我在机器上安装并运行它时,它将被使用(英特尔 NUC NUC7CJYH)应用程序的 CPU 使用率 > 94%,导致机器上的使用率为 100%。

目前,该应用程序会扫描用户的二维码两次——第一次是员工的二维码,第二次是他们从事的项目编号的二维码。该应用程序使用 ZXing.Net 解码 QR 码,并使用 AForge.Net 访问网络摄像头。

我已经运行了 VS Profiler,这是结果的屏幕截图: VS Profiler Output

根据 VS Profiler 的结果,有 4 个方法调用使用了最多的 CPU 时间,大概我应该关注:

我不确定如何优化代码。我已经查看了为两个 DispatcherTimer 中的每一个设置 DispactherPriority,但在测试中这对应用程序的 CPU 使用率没有影响,并且会干扰每个 DispatcherTimer 的间隔。我还尝试将我在 qrTimer_Tick 方法中配置的 3 个 BarcodeReader 选项更改为 false,这产生了大约 1% 的改进。但是,我认为这可以忽略不计,因为它取决于用户将 QR 码放在相机前的速度以及 qrTimer_Tick 是否已经触发等因素。

有什么我想念的吗?难道仅仅是该应用程序压倒了它运行的 NUC 机器吗?

编辑 在遵循 kennyzx 和 lerthe61 的建议后,我设法将 NUC NUC7CJYH 上的应用程序 CPU 使用率降低到峰值时的约 58%。最大的好处是删除了每秒调用 timer_Tick 事件处理程序的 DispatcherTimer 对象。在我进行此更改后不久运行 VS Profiler 显示我的开发机器上的峰值 CPU 使用率为 18%,这是在应用程序启动后不久,必须自行运行。

在 lerthe61 的输入之后,我查看了我对 MemoryStream 和 Bitmap 对象的使用。videoSource_NewFrame 方法现在如下所示:

void videoSource_NewFrame(object sender, NewFrameEventArgs eventArgs)
        {
            try
            {
                BitmapImage bi;

                capturedImage = (Bitmap)eventArgs.Frame.Clone();
                bi = new BitmapImage();
                bi.BeginInit();
                ms = new MemoryStream();
                capturedImage.Save(ms, ImageFormat.Bmp);
                ms.Seek(0, SeekOrigin.Begin);
                bi.StreamSource = ms;
                bi.CacheOption = BitmapCacheOption.OnLoad;
                bi.EndInit();
                bi.Freeze();
                Dispatcher.BeginInvoke(new ThreadStart(delegate { imgSource.Source = bi; }));
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error with attaching video frame.\n " + ex.Message);
                MessageBox.Show("An error occurred. \nPlease contact the Systems Development team for assistance.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }

        }          

我现在在 qrTimer_Tick 方法中使用了 lock 来锁定来自网络摄像头的当前捕获的图像:

if (capturedImage != null)
{
   lock (_qrTimerLock)
   {
      result = reader.Decode(capturedImage);
   }
}

尽管我使用了锁,但该应用程序偶尔会抛出错误“对象当前正在其他地方使用”。我对代码的重构在删除 timer_Tick 之上对应用程序的 CPU 使用效率影响不大,所以我可以保持原样,但这显然效率较低。

标签: c#wpfaforgezxing.net

解决方案


我决定移除每秒运行的 DispatcherTimer,留下每 3 秒运行的第二个 DispatcherTimer 对象。仅使用此修复程序的应用程序的性能是有利的。

感谢大家的帮助!


推荐阅读