为什么 async wait 操作仍然耗时

use*_*851 1 c# multithreading asynchronous task-parallel-library async-await

我有一个 Winforms 应用程序,我正在尝试打印一个包含多个图层的 pdf 文档。但问题是,这所有操作都在 UI 线程上运行,并且长时间挂起 UI(无响应)。我知道,发生这种情况是因为 UI 线程被阻塞,所以我尝试借助强大的async/await关键字使此操作异步,但我的长时间运行方法仍然不是异步的。它没有从任务中发出await,并且操作仍然与同步操作一样花费相同的时间。

我尝试过的:

请看下面:

/// <summary>
  /// Show Print Dialog
  /// </summary>
  private void ShowPrintDialog()
  {
     // Initialize print dialog
     System.Windows.Controls.PrintDialog prtDialog = new System.Windows.Controls.PrintDialog();

     prtDialog.PageRangeSelection = PageRangeSelection.AllPages;
     prtDialog.UserPageRangeEnabled = false;

     _printOptions.PrintQueue = null;
     _printOptions.PrintTicket = null;
   
     Enabled = false;

     // if there is a default printer then set it
     string defaulPrinter = prtDialog.PrintQueue == null ? string.Empty : prtDialog.PrintQueue.FullName;

     // Display the dialog. This returns true if the user selects the Print button.
     if (prtDialog.ShowDialog() == true)
     {
        _printOptions.PrintQueue = prtDialog.PrintQueue;
        _printOptions.PrintTicket = prtDialog.PrintTicket;
        _printOptions.UseDefaultPrinter = (defaulPrinter == prtDialog.PrintQueue.FullName);
     }

     // Re-enable the form
     Enabled = true;
  }





 /// <summary>
  /// Event raised when user clicks Print
  /// </summary>
  /// <param name="sender">Source of the event</param>
  /// <param name="e">Event specific arguments</param>
  private void cmdOk_Click(object sender, EventArgs e)
  {
        ShowPrintDialog();

        if (_printOptions.PrintTicket != null)
        {
           //Set search Options
           _print.ExportDataItem = true;
           _print.FileName = SearchTemplateName;

           //shows progress bar form.
           using (frmPrintSearchResultsProgress frmProgress =
                       new frmPrintSearchResultsProgress(_print, this, _printOptions))
           {
              frmProgress.ShowDialog(this);
           }
           if (_print.ExportDataItem && !_print.DataItemExported && !_print.CancelExport)
           {
              MessageBox.Show("No Document printed.");
           }
        }

        //Store selected options for current user
        SaveOptions();

        if (!SkipExport)
           Close();
}



 /// <summary>
  /// Event raised when progress form is shown.
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  private async void frmExportSearchResultsProgress_Shown(object sender, EventArgs e)
  {
     try
     {
        Application.DoEvents();

        dispatcher = Dispatcher.CurrentDispatcher;
        // record export/print job start time
        _startedUtc = DateTime.UtcNow;

        _print.WritingToPdfIndicator = lblWritingPdfFile;

        lblProgress.Text = Properties.Resources.PrintSearchResults;
        await dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(DoDataItemPrint));
     }
}



/// <summary>
  /// Prints the selected data items.
  /// </summary>
  private void DoDataItemPrint()
  {
     // LONG RUNNING OPERATIONS..
     // THIS OPERATION IS BLOCKING THE UI.
  }
Run Code Online (Sandbox Code Playgroud)

因此,正如上面代码中提到的,当我打开时,PringDialogForm它会打开一个进度栏表单来查看打印文档的进度,从这里frmExportSearchResultsProgress_Shown()触发事件并在其中调用该方法,DoDataItemPrint()该方法非常耗时。因此,我尝试将frmExportSearchResultsProgress_Shown事件设为async/await但操作仍然花费与之前相同的时间。

谁能建议我哪里做错了?

Mar*_*ell 6

  • 你的frmExportSearchResultsProgress_Shown方法在 UI 线程上启动
  • 然后它分派DoDataItemPrint到...相同的 UI 线程
  • 它安排了一个延续(通过await),以便当不完整的事情发生时,我们回到frmExportSearchResultsProgress_Shown,并且由于这里可能有一个同步上下文,同步上下文捕获(隐式在 中await)会将我们推向... UI线

正如你所看到的:一切都发生在 UI 线程上

如果不想阻塞UI,就需要脱离UI线程。这可能就像使用Task.Runinvoke一样简单DoDataItemPrint,但是如果不知道该代码包含什么内容,就不可能知道您是否正在使用线程绑定控件来进行打印。如果你是……就很难摆脱这一点。