C#巧妙使用關鍵字async/await


原文鏈接(程序傑傑):https://www.cnblogs.com/ningxinjie/p/12008561.html

 

經過一番的探索,終於搞清楚關鍵字async/await 在.net4.5之后可用的巧妙之處,在這里記錄一下也與大家分享一下個人的心得體會

async:異步執行

await:異步執行中的等待其執行完(最大的優點是它是后台等待,因此不阻塞GUI,界面交互非常的好)

 

使用async方法要定義async Task或者async Task<T> 最好不要定義async void方法來調用,async void是處理程序等,總結結論就是要使用async Task或者async Task<T> 

使用asyn方法,可以用同步的格式,執行異步的代碼,如下:

 1         int a = 0;
 2         private void button1_Click(object sender, EventArgs e)
 3         {
 4             Task.Run(()=> {
 5                 Stopwatch sw = new Stopwatch();
 6                 sw.Start();
 7                 Thread.Sleep(2000);
 8                 sw.Stop();
 9                 SetText(textBox1,this, sw.ElapsedMilliseconds.ToString());
10             });
11             var eee=Ce_async();//前面接收值,這樣方法立即返回,主線程繼續執行
12             //eee.IsCompleted
13             textBox3.Text = "主線程繼續向下執行";
14 
15 
16         }
17         private async Task Ce_async()
18         {
19             await Task.Run(async ()=> {
20                 while (true)
21                 {
22                     await Task.Delay(100);//Thread.Sleep(2000);23                     a += 1;
24                     SetText(textBox2, this, a.ToString());
25                 }
26             });
27         }
28 
29 
30 
31         private delegate void SetTextdelegate(Control cr,Form f,string str);
32         private void SetText(Control cr, Form f, string str)
33         {
34             if (f.InvokeRequired) { f.Invoke(new SetTextdelegate(SetText), cr, f, str); }
35             else { cr.Text = str; }
36         }

正如上圖第11行注釋,使用接收值來接收async方法,該方法會立即返回值,主程序繼續向下執行,該方法后台繼續跑。

 

那么肯定有小伙伴與我當初有同樣的疑惑,這樣我執行用線程在這里執行不也可以嗎?為什么要用async關鍵字呢,他到底有什么好處?

 

比如有一種情況:我的主線程如何有需要休眠等待的情況,那么直接使用Thread.Sleep(),會使界面卡死,如果此時我將方法修改為async,那么只需要await Task.Delay() 這樣也會等待時間完成后再向下執行,但是它不會使主界面處於假死狀態,如下:

 1    private async void button1_Click(object sender, EventArgs e)
 2         {
 3             await Task.Delay(1000);
 4             var aaa=Task.Run(() =>
 5             {
 6                 Stopwatch sw = new Stopwatch();
 7                 sw.Start();
 8                 Thread.Sleep(2000);
 9                 sw.Stop();
10                 SetText(textBox1, this, sw.ElapsedMilliseconds.ToString());
11             });
12             var eee=Ce_async();//前面接收值,這樣方法立即返回,主線程繼續執行
13             //eee.IsCompleted
14             textBox3.Text = "主線程繼續向下執行";
15         }

 

再次重復一點,在async方法中使用接收值來接收Task,會使得Task不必加上await關鍵字而被迫使得主線程需要等待它執行完才能向下執行,接收值的目的就是立即得到返回值

使用接收值來接收Task會直接返回,代碼繼續向下執行,這一點很重要!!!

上圖的第3行,如下:

await Task.Delay(1000);

其中await只能用在異步方法中,await會使得該線程等待await處的線程執行完,方可執行下方代碼,正如該處代碼所示,使用await Task.Delay(100); 代替 Thread.Sleep(100)

 

對於有返回值的這樣來寫:

Form1中按鈕代碼如下:

  private async void button1_Click(object sender, EventArgs e)
        {
           string a= await new Class1().Ceshifunc();
           MessageBox.Show(a);
        }

 

執行的Class1類方法為:

  public class Class1
    {
        private static readonly object obj = new object();
        public Task<String> Ceshifunc()
        {
            lock (obj)
            {
                var task = Task.Run(()=>
                {
                    Thread.Sleep(5000);
                    return "ok";
                });
                return task;
            }
        }
    }

 這樣操作無卡頓,但是仍然無法實現lock內無法await,因為lock內的代碼是task,他不會等待task執行完再返回,而是返回出去再執行,因此相當於沒lock一樣

 

我將所有代碼放入Form1下

 

 

    private static readonly object obj = new object();
        public Task<String> Ceshifunc(string str, Form form, TextBox tb)
        {
            var task = Task.Run(() =>
            {
                lock (obj)
                {
                    string aa = label1.Text;
                    SetText(label1, this, aa + "1");
                    Thread.Sleep(2000);
                    SetText(tb, form, str);
                    return str;
                }
            });
            return task;
        }

        public Action<Control, Form, string> setText;
        public void SetText(Control tb, Form form, string str)
        {
            setText += SetText;
            if (form.InvokeRequired) { form.Invoke(setText, tb, form, str); }
            else { tb.Text = str; }
        }

 

按鈕事件為:

  private async void button1_Click(object sender, EventArgs e)
        {
            string a = await Ceshifunc("b1", this, textBox1);
        }

 

 這樣就可以實現了變相解決lock內的await使用

 

 

 

個人推薦另一個博客原文鏈接地址:https://www.cnblogs.com/mqxs/p/6550274.html

 

 以上就是個人的心得體會,(轉載請注明)(程序傑傑)原文鏈接:https://www.cnblogs.com/ningxinjie/p/12008561.html



 


免責聲明!

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



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