請考慮將 "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 + "\r\n";
            Method1();
            txt_boxMessage.Text += "Method1 end:" + DateTime.Now + "\r\n";
            txt_boxMessage.Text += "Method1 end:" + DateTime.Now + "\r\n";
            Method2();
            txt_boxMessage.Text += "Method1 end:" + DateTime.Now + "\r\n";
           
            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 + "\r\n";
            await Method1();
            txt_boxMessage.Text += "Method1 end:" + DateTime.Now + "\r\n";
            txt_boxMessage.Text += "Method1 end:" + DateTime.Now + "\r\n";
            Method2();
            txt_boxMessage.Text += "Method1 end:" + DateTime.Now + "\r\n";
           
            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 + "\r\n";
            await Method1();
            txt_boxMessage.Text += "Method1 end:" + DateTime.Now + "\r\n";
            txt_boxMessage.Text += "Method2 begin:" + DateTime.Now + "\r\n";
            await Method2();
            txt_boxMessage.Text += "Method2 end:" + DateTime.Now + "\r\n";
           
            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關鍵字進行調用,這時程序的運行結果可能會變得非常詭異。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM