C#5 Async Await .Task.Factory.StartNew取消

时间:2013-02-22 15:25:48

标签: c# task-parallel-library async-await

我有实现取消令牌的异步代码。它正在工作,但我不确定这是否是正确的方法,所以我只想要反馈。

以下是实际代码:

    /// <summary>
    /// 
    /// </summary>
    private async void SaveData() {

        if (GetActiveServiceRequest() != null)
        {
            var tokenSource = new System.Threading.CancellationTokenSource();


            this.ShowWizardPleaseWait("Saving data...");

            var someTask = System.Threading.Tasks.Task<bool>.Factory.StartNew(() =>
            {

                bool returnVal = false;

                // Set sleep of 7 seconds to test the 5 seconds timeout.
                System.Threading.Thread.Sleep(7000);

                if (!tokenSource.IsCancellationRequested)
                {
                    // if not cancelled then save data

                    App.Data.EmployeeWCF ws = new App.Data.EmployeeWCF ();
                    returnVal = ws.UpdateData(_employee.Data);
                    ws.Dispose();
                }

                return returnVal;

            }, tokenSource.Token);


            if (await System.Threading.Tasks.Task.WhenAny(someTask, System.Threading.Tasks.Task.Delay(5000)) == someTask)
            {
                // Completed
                this.HideWizardPleaseWait();
                if (someTask.Result)
                {
                    this.DialogResult = System.Windows.Forms.DialogResult.OK;
                }
                else
                {
                    this.DialogResult = System.Windows.Forms.DialogResult.Abort;
                }
                btnOK.Enabled = true;
                this.Close();
            }
            else
            {
                tokenSource.Cancel();

                // Timeout logic
                this.HideWizardPleaseWait();
                MessageBox.Show("Timeout. Please try again.")
            }


        }
    }

异步/等待/取消代码是否已得到很好的实施?

感谢并感谢您的反馈。

1 个答案:

答案 0 :(得分:5)

通常,您应该使用ThrowIfCancellationRequested。这将在取消状态下完成返回的Task,而不是在&#34;成功完成&#34;结果为false的州。

其他要点:

  • 避免使用async void。这应该是async Task,除非它是一个事件处理程序。
  • Prefer Task.Run over TaskFactory.StartNew
  • 使用using
  • 如果您只是使用CancellationTokenSource作为超时,那么它具有特殊功能。通过Task.DelayTask.WhenAny创建单独的任务是不必要的。

以下是更新后的代码:

private async Task SaveData()
{
    if (GetActiveServiceRequest() != null)
    {
        var tokenSource = new System.Threading.CancellationTokenSource(TimeSpan.FromSeconds(5));
        var token = tokenSource.Token;

        this.ShowWizardPleaseWait("Saving data...");

        var someTask = System.Threading.Tasks.Task.Run(() =>
        {
            // Set sleep of 7 seconds to test the 5 seconds timeout.
            System.Threading.Thread.Sleep(7000);

            // if not cancelled then save data
            token.ThrowIfCancellationRequested();
            using (App.Data.EmployeeWCF ws = new App.Data.EmployeeWCF())
            {
                return ws.UpdateData(_employee.Data);
            }
        }, token);

        try
        {
            var result = await someTask;

            // Completed
            this.HideWizardPleaseWait();
            if (result)
            {
                this.DialogResult = System.Windows.Forms.DialogResult.OK;
            }
            else
            {
                this.DialogResult = System.Windows.Forms.DialogResult.Abort;
            }
            btnOK.Enabled = true;
            this.Close();
        }
        catch (OperationCanceledException)
        {
            // Timeout logic
            this.HideWizardPleaseWait();
            MessageBox.Show("Timeout. Please try again.")
        }
    }
}