• 请考虑将 "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关键字进行调用,这时程序的运行结果可能会变得非常诡异。

  • 相关阅读:
    CSS3自适应布局单位 —— vw,vh
    JS 设计模式四 -- 模块模式
    JS 设计模式三 -- 策略模式
    JS 设计模式
    JS 设计模式二 -- 单例模式
    JS 设计模式一 -- 原型模式
    JS 灵活使用 console 调试
    JS 优化条件语句的5个技巧
    JS 函数节流与防抖
    前端性能优化
  • 原文地址:https://www.cnblogs.com/lnwuyaowei/p/12672866.html
Copyright © 2020-2023  润新知