【问题标题】:Unable to cancel Async/Awaiting call on button click单击按钮时无法取消异步/等待调用
【发布时间】:2016-12-19 10:14:34
【问题描述】:

我无法在单击取消按钮时取消异步/等待调用。如果在网格中加载数据需要很长时间,我想取消查询。我是使用 async/await 方法的新手,并参考了许多示例,但无法锻炼。请看我下面的代码,请帮忙。谢谢

    namespace MyFirstAsync
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        CancellationTokenSource cts ;
        private async void btnExecute_Click(object sender, EventArgs e)
        {
            cts = new CancellationTokenSource();
            try
            {
                string connectionString = "Data Source=G50-80;Initial Catalog=HPSF_Compdb;User ID=sa;Password=sql@2012";
                string sqlQuery = "select top 900000 * from requestevent.result";
                SqlConnection conn = new SqlConnection(connectionString);
                SqlCommand cmd = new SqlCommand(sqlQuery, conn);
                await conn.OpenAsync(cts.Token);
                SqlDataReader reader = await cmd.ExecuteReaderAsync(cts.Token);
                DataTable dt = new DataTable();
                //cts.Cancel();
                await Task.Run(() => dt.Load(reader), cts.Token);
                gvData.Invoke(new gvDelegate(UpdateDataToGrid), new object[] { dt });
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

        }

        public delegate void gvDelegate(DataTable dt);
        public void UpdateDataToGrid(DataTable dt)
        {
            gvData.DataSource = dt;
        }



        private void btncancel_Click(object sender, EventArgs e)
        {
            cts.Cancel();
        }



    }
}

【问题讨论】:

  • 那么当你运行这段代码时会发生什么?你有任何例外吗?您提供的详细信息越多,您的问题就越有可能得到解答。
  • 嗨鲁本,不,它没有抛出任何错误,只是完成了查询并将数据加载到网格视图而不接受取消请求。我不知道如何调试它和排除故障。

标签: c# async-await


【解决方案1】:

问题出在这行代码上:

await Task.Run(() => dt.Load(reader), cts.Token);

与您的预期相反,传递给Task.Run 的CancellationToken 只会取消该任务的启动,而不是任务本身。也就是说,Load一旦启动,就无法取消。

理想情况下,您应该在现代代码中使用 DataTables 以​​外的其他内容;其他数据库 API 已更新以支持取消。如果这是不可能的,那么您可以在答案中使用CancellationTokenRegistration。但是,您应该不使用Result - 改为使用await:

using (CancellationTokenRegistration ctr = cts.Token.Register(() => cmd.Cancel()))
using (var reader = await cmd.ExecuteReaderAsync(cts.Token))
    dt.Load(reader);

【讨论】:

    【解决方案2】:

    我找到了上述问题的解决方案,只是将数据加载方式更改为数据表。请参考用新代码替换的注释旧代码,它按预期工作得很好。新代码我只是复制和粘贴,但我仍然不知道如何描述新代码的工作方式,因为我是新手。但它对我有用。如果您区分两者,请解释一下。

    using (CancellationTokenRegistration ctr = cts.Token.Register(() => cmd.Cancel()))
                {
                    using (var reader = cmd.ExecuteReaderAsync(cts.Token))
                    {
                        dt.Load(reader.Result);
                    }
                }
                //SqlDataReader reader = await cmd.ExecuteReaderAsync(cts.Token);
                //DataTable dt = new DataTable();
                //await Task.Run(() => dt.Load(reader), cts.Token);
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-06
    • 2020-08-05
    • 1970-01-01
    • 2020-04-23
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    相关资源
    最近更新 更多