为啥异步等待操作仍然很耗时

Posted

技术标签:

【中文标题】为啥异步等待操作仍然很耗时【英文标题】:Why async await operation is still time consuming为什么异步等待操作仍然很耗时 【发布时间】:2021-11-21 02:24:10 【问题描述】:

我有一个 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.
  

所以,正如上面代码中提到的,当我打开PringDialogForm 时,它正在打开一个进度条表单以查看打印文档的进度,并从这里触发frmExportSearchResultsProgress_Shown() 事件,在其中,我正在调用DoDataItemPrint() 方法很耗时。 所以,我尝试将frmExportSearchResultsProgress_Shown 事件设置为async/await,但仍然需要与之前相同的时间。

谁能告诉我哪里做错了?

【问题讨论】:

所有代码都在 UI 线程上运行。没有什么异步的 请删除Application.DoEvents()。这是邪恶的。它仅在与 2001 年的 VB6 兼容的框架中。它可能会导致重入问题,甚至锁定您的 UI。您应该立即删除它。 【参考方案1】: 您的 frmExportSearchResultsProgress_Shown 方法在 UI 线程上启动 然后它将DoDataItemPrint 分派到...同一个 UI 线程 它安排一个延续(通过await),这样当不完整的事情发生时,我们回到frmExportSearchResultsProgress_Shown,由于这里可能有一个同步上下文,同步上下文捕获(隐含在@ 987654325@) 会将我们推向... UI 线程

如您所见:一切都发生在UI 线程上

如果你不想阻塞 UI,你需要离开 UI 线程。这可以像使用Task.Run 调用DoDataItemPrint 一样简单,但是如果不知道该代码包含什么,就不可能知道您是否使用线程绑定控件进行打印。如果你是......将很难摆脱它。

【讨论】:

以上是关于为啥异步等待操作仍然很耗时的主要内容,如果未能解决你的问题,请参考以下文章

Async异步编程简介

dart基础语法

dart基础语法

dart基础语法

django 使用celery 实现异步任务

SpringBoot实现http请求的异步长轮询【2】— AsyncHandlerInterceptor方式