等待的方法调用似乎没有完成

Awaited method call doesnt appear to complete

我刚开始学习异步编码,运行陷入了困境。

这就是我想要做的。

  1. 我有一个异步调用两个等待方法的方法。出于测试目的,每个方法都调用一个执行 WAITFOR DELAY 'xxx'.

    的存储过程
  2. 在每个方法调用中,另一个方法需要 运行 在它旁边生成三个加载点附加到传入的文本值。

  3. 所以当 await Task.Run(() => DisableReplication("Disable Replication")) 是 运行ning 时(调用存储过程 10 秒)它将显示

    Disabling Replication.
    Disabling Replication..
    Disabling Replication...

    直到该存储过程完成,然后它应该说

    Disabling Replication - Complete

    然后它应该调用 await Task.Run(() => ImportWeights("Importing Weights")),例如,proc 需要 20 秒才能完成。所以会显示

    Importing Weights.
    Importing Weights..
    Importing Weights...

    然后一旦完成它会说

    Import Weights - Complete.

在每个方法中,都有一个布尔值在方法完成后从 false 设置为 true。该值用于 while 循环中的 ShowProgressText 方法。一旦该值设置为 true,它就会爆发。

目前它在显示 'Disabling Replication' 方面做得很好,但是一旦该方法完成,它就会开始在 'Disabling Replication' 和 'Importing Weights' 之间切换。我假设 Disabling Replication 方法已经完成,所以我不确定为什么它会继续拾取文本。我认为问题出在 ShowProgressText 方法上。

有谁知道我做错了什么,也许我能以某种方式简化它吗?

这是一个显示它正在做什么的 .gif,下面是我正在使用的代码。

using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace DirectMailSpendManagement
{
    public partial class FrmRapport : AestheticsFormBase
    {    
        #region Instantiations
        private readonly RapportDataAccess access = new RapportDataAccess();
        private readonly Panel panel = new Panel();
        #endregion
        
        #region Fields
        private bool IsCompleted;
        #endregion
        
        #region Constructors
        public FrmRapport()
        {
            InitializeComponent();
        }
        #endregion
        
        #region Private Methods
        private void BtnGetRapportFile(object sender, EventArgs e)
        {
            _ = LoadRapport();
        }
        
        private async Task LoadRapport()
        {
            await Task.Run(() => DisableReplication("Disable Replication"));
            await Task.Run(() => ImportWeights("Importing Weights"));
        }
        
        private void DisableReplication(string txt)
        {
            IsCompleted = false;
            Task.Run(() => ShowProgressText(txt));
            access.DisableReplication();
        }
        
        private void ImportWeights(string txt)
        {
            IsCompleted = false;
            Task.Run(() => ShowProgressText(txt));
            access.ImportAndCalculateWeights(panel.PanelNumber, "", "", "");
        }
        
        private void ShowProgressText(string txt)
        {
            var count = 0;
            var logText = new StringBuilder();
        
            logText.Append(txt);
            var baseLen = logText.Length;
        
            while (!IsCompleted)
            {
                Thread.Sleep(300);
                if (count >= 3)
                {
                    logText.Remove(baseLen, count);
                    count = 0;
                }
        
                logText.Append(".");
                count++;
        
                BeginInvoke(new Action(() => { UpdateProgressText(logText.ToString()); }));
            }
        
            BeginInvoke(new Action(() => { UpdateProgressText(txt + " - Complete"); }));
        }
        
        private void UpdateProgressText(string txt)
        {
            lblProgress.Text = txt;
        }
        #endregion
    }
}

问题是您有两个单独的任务 运行 调用 ShowProgressText。 Task.Run() 不是您通常使用的东西,除非您与不使用 C# async/await 模式的代码交互。所以也许 LoadRapport 可能是这样的:

    bool IsCompleted;
    string LogText;

    private async Task LoadRapport()
    {
        LogText = "Disable Replication";
        IsCompleted = false;

        _ = ShowStatus(); // start this task but don't wait for it to finish.

        // Start these long running methods on a separate non UI thread using Task.Run.
        await Task.Run(() => DisableReplication());

        LogText = "Importing Weights";

        await Task.Run(() => ImportWeights());

        IsCompleted = true; // tell ShowStatus to complete.
    }

ShowStatus 可能是这样的:

    async Task ShowStatus()
    {
        while (!IsCompleted) {
            BeginInvoke(new Action(() =>
            {
                UpdateProgressText(this.LogText);
            })); ;
            await Task.Delay(200);
        }

        UpdateProgressText("Completed");
    }

我还会记得在这个漫长的 运行 过程中禁用调用 BtnGetRapportFile 的按钮,这样用户就不会单击它 10 次并获得 10 个单独的线程 运行 调用您的 SQL 服务器...