使用 Parallel.ForEach 与 TPL.Dataflow 或其他将 OCR 应用于大量

我正在创建一个应用程序来批处理 OCR 图像,现在我正在使用异步 Parallel.ForEach 方法来遍历包含文件名和 OCR 文本字段的对象列表(打印输出)。


我想知道这是否是解决此问题的最佳方法。我读过有关 TPL.Dataflow 的文章,虽然它看起来有点矫枉过正,但我想知道使用更复杂的方法是否更好,因为我可能会同时处理数百个文件,而且我不确定是否创建了数百个任务是很好的做法。另外,我读过在 Parallel.ForEach 中使用 Interlocked.Increment 是不好的做法,我应该将其转换为 Parallel.For 吗?下面是我当前的实现:


private async void BatchOCR_Click(object sender, EventArgs e) {

   //some UI stuff

   source = new CancellationTokenSource();

   progressBar.Value = 0;

   int counter = 0;

   IProgress<int> progress = new Progress<int>(i => { progressBar.Value = (int)Math.Round((float)(i)*100 / fileList.Items.Count, 0); });


   await Task.Run(() => RunBatchOCR(ListOfPrintouts,progress,counter), source.Token);

   //some UI stuff

}

private async Task RunBatchOCR(List<Printout> printouts,IProgress<int> progress, int counter) {

   progress.Report(0);

   Parallel.ForEach(printouts, (printout,state) =>

      {

         try

         {

            source.Token.ThrowIfCancellationRequested();

         }

         catch

         {

            Console.WriteLine("Task was cancelled");

            cancelButton.Enabled = false;

            state.Break();

          }

          finally

          {

             Interlocked.Increment(ref counter);

          }

          printout.OcrHelper.runOCR(); //loads bitmap and extracts text

          progress.Report(counter);

          Console.WriteLine(counter.ToString());

    });

}


月关宝盒
浏览 87回答 1
1回答

胡子哥哥

我不确定创建数百个任务是否是一个好习惯没关系。Parallel使用智能分区。关于代码的其余部分,Interlocked可以用作计数器,但您不想在没有互锁障碍的情况下访问相同的变量。该CancellationToken代码需要简化:private async Task RunBatchOCR(List<Printout> printouts, IProgress<int> progress){&nbsp; int counter = 0;&nbsp; progress?.Report(0);&nbsp; try&nbsp; {&nbsp; &nbsp; Parallel.ForEach(printouts, new ParallelOptions { CancellationToken = source.Token }, printout =>&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; printout.OcrHelper.runOCR(); //loads bitmap and extracts text&nbsp; &nbsp; &nbsp; var update = Interlocked.Increment(ref counter);&nbsp; &nbsp; &nbsp; progress?.Report(update);&nbsp; &nbsp; &nbsp; Console.WriteLine(update.ToString());&nbsp; &nbsp; });&nbsp; }&nbsp; catch (OperationCanceledException)&nbsp; {&nbsp; &nbsp; Console.WriteLine("Task was cancelled");&nbsp; &nbsp; cancelButton.Enabled = false;&nbsp; }}
打开App,查看更多内容
随时随地看视频慕课网APP