请考虑将 "await" 运算符应用于调用结果

界面:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace taskTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        string str;
        public MainWindow()
        {
            InitializeComponent();
        }

        public  async Task<int> Method1()
        {
            int count = 0;
            await Task.Run(() =>
            {
                for (int i = 0; i < 500; i++)
                {
                   
                    str += "A";
                    count += 1;
                    Thread.Sleep(TimeSpan.FromSeconds(0.01));
                }
            }
        );
            return count;
        }
        public void Method2()
        {
            for (int i = 0; i < 200; i++)
            {
                str += "B";
            }
        }

        private void btn1_Click(object sender, RoutedEventArgs e)
        {
            str = "";
            txt_boxMessage.Text = "";
            txt_boxMessage.Text = "Method1 begin:" + DateTime.Now + "
";
            Method1();
            txt_boxMessage.Text += "Method1 end:" + DateTime.Now + "
";
            txt_boxMessage.Text += "Method1 end:" + DateTime.Now + "
";
            Method2();
            txt_boxMessage.Text += "Method1 end:" + DateTime.Now + "
";
           
            this.txt_box1.Text = str;

            int numA = Regex.Matches(str, "A").Count;
            int numB = Regex.Matches(str, "B").Count;

            MessageBox.Show("A:" + numA, "B:" + numB);
        }

        private void btn2_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show(str);
        }
    }
}

如查按上面的代码写一段程序,语法检查会有一小段提示:

“由于此调用不会等待,因此在此调用完成之前将会继续执行当前方法。请考虑将 "await" 运算符应用于调用结果。”

运行程序,点按钮1,结果:

 可以看到,由于Method1异步执行,只有其中一部分数据返回。注意这时程序的界面没有阻塞,这就是异步编程带来的好处。

之所以A只返回了一个字符,是由于执行的时间不够,程序还在后台继续生成字符串。

我们再点按钮2,这时可以看到生成的完整字符串:

异步调用虽然不阻塞主线程,但是程序运行的结果并不是我们想要的,所以更改代码如下:

private async Task btn1_ClickAsync()
        {
            str = "";
            txt_boxMessage.Text = "";
            txt_boxMessage.Text = "Method1 begin:" + DateTime.Now + "
";
            await Method1();
            txt_boxMessage.Text += "Method1 end:" + DateTime.Now + "
";
            txt_boxMessage.Text += "Method1 end:" + DateTime.Now + "
";
            Method2();
            txt_boxMessage.Text += "Method1 end:" + DateTime.Now + "
";
           
            this.txt_box1.Text = str;

            int numA = Regex.Matches(str, "A").Count;
            int numB = Regex.Matches(str, "B").Count;

            MessageBox.Show("A:" + numA, "B:" + numB);
        }
        private void btn1_Click(object sender, RoutedEventArgs e)
        {
            btn1_ClickAsync();
        }

这时再点击按钮1:

程序开始运行结果如下,注意此时UI线程仍然未被阻塞,用户仍然可以进行界面操作:

大约过了5秒

 

所以await async的意思就是:等待异步执行

好处是在这个等待过程中,主界面的UI线程没有被阻塞,还可以进行其他操作。

继续更改代码,将Method2也改为异步执行

public async Task<int> Method2()
        {
            int count = 0;
            await Task.Run(() =>
            {
                for (int i = 0; i < 500; i++)
                {

                    str += "B";
                    count += 1;
                    Thread.Sleep(TimeSpan.FromSeconds(0.01));
                }
            }
        );
            return count;
        }

这时的结果如下:

 可以看到click事件完成后,Method2还没有运行完毕,我们点击按钮2,可以看到完整的运行结果:

  我们在调用 Method2时也加上关键字await,这时代码如下:

 private async Task btn1_ClickAsync()
        {
            str = "";
            txt_boxMessage.Text = "";
            txt_boxMessage.Text = "Method1 begin:" + DateTime.Now + "
";
            await Method1();
            txt_boxMessage.Text += "Method1 end:" + DateTime.Now + "
";
            txt_boxMessage.Text += "Method2 begin:" + DateTime.Now + "
";
            await Method2();
            txt_boxMessage.Text += "Method2 end:" + DateTime.Now + "
";
           
            this.txt_box1.Text = str;

            int numA = Regex.Matches(str, "A").Count;
            int numB = Regex.Matches(str, "B").Count;

            MessageBox.Show("A:" + numA, "B:" + numB);
        }

运行程序,点击按钮1,大约10秒后,可以看到运行结果:

 总结:

1、不使用await关键字,在异步线程中,由于可能没有足够的时间等待返回结果,所以可能不会在预期的代码段上取得正确的结果。

2、Method1使用await关键字异步执行,Method2为不涉及异步执行的方法,会在Method2处阻塞主线程。

3、都使用await关键字,在异步线程中,异步方法是按队列执行的,结果与同步方法一样。好处是没有阻塞主线程执行其它任务。

所以在asp.net core中的代码:

 await TryUpdateModelAsync

 await _context.SaveChangesAsync()

是顺序执行的,后面的代码无论怎么写,都必然是顺序执行。

但有一点除外,那就是:同步调用异步方法,也就是异步方法前不加await关键字进行调用,这时程序的运行结果可能会变得非常诡异。

原文地址:https://www.cnblogs.com/lnwuyaowei/p/12672866.html