c# 異步之async/await ,Task


使用異步的好處是什么呢?

我認為有如下好處:

1.用戶體驗性好

比如一個表格需要綁定大量數據,整個過程完成需要十幾秒鍾,而用戶希望在這過程中,可以點擊其它地方

(若需要界面不卡死,常用的一種方法是使用backgroundworker (實際上也是異步,新開一個線程來執行,用戶體驗性好了,但是實際執行效率並沒有得到提升),點擊按鈕執行BackgroundWorker.RunWorkerAsync,觸發DoWork事件)

2.提高程序執行速度

假設一個button按鈕里的代碼有三部分,Code1執行需要10秒,Code2執行需要20秒,Code3執行需要30秒,因為程序代碼解讀自上而下,傳統的同步方式會等待每一句代碼執行完成后,才會執行下一句代碼,所以點擊此button后,需要60秒才能全部執行結束,界面卡死消失;

而async/await異步的原理是Code1委托給線程1處理了,主線程不管了,程序繼續往下執行,接着Code2委托給線程2執行,程序繼續往下執行,接着Code3直接處理就好(不用委托異步調用),Button執行時間為最大的一部分,也就是30秒,並且界面不卡死

 

異步使用

async 提供上下文信息,提示編譯器里面會包含await方法,async必須在返回類型之前,比如private static async Task<int>... 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class frmAsync : Form
    {
        public frmAsync()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 程序執行時間10秒
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async   void btnAsync_Click(object sender, EventArgs e)
        {
          var count= await GetCountValue(); //如果不加await,因為這是個異步方法,不會等待,變量count得到的值是int類型
          MessageBox.Show(count.ToString());
       
        }


        private async Task<int> GetCountValue()
        {

            Stopwatch sw = new Stopwatch();
            sw.Start();
            //Func<int,int> Func = Calc;
            //Func(1000);

            //Task為線程池的封裝模式。
            Task<int> result = Task.Run<int>(() =>
            {
                return Calc(1000);
            });
            //方法沒有參數傳入,有返回值
            //Task<string> result2 = Task.Run<string>
            //    (() => { return GetCalc(); });


            //await result2;

            int finialValue = 0;
            int countValue = 0;
            //可以在匿名函數里面直接寫方法體
            //Task<int> result2 = Task.Run<int>(() =>
            //{

            //    for (int i = 0; i < 1000; i++)
            //    {
            //        System.Threading.Thread.Sleep(10);
            //        countValue += i;
            //    }
            //    return countValue;

            //});

            //直接執行
                for (int i = 0; i < 1000; i++)
                {
                    System.Threading.Thread.Sleep(10);
                    countValue += i;
                }

            await result;
           // await result2;

            #region 這樣寫耗時一樣,但是界面會卡死,直到運行結束
            //Task[] para = { result, result2 };
            //Task.WaitAll(para);
            #endregion


            finialValue = countValue + result.Result;

            sw.Stop();
            this.richTextBox1.Text = "最終計算結果:" + finialValue + "異步方法耗時:" + (sw.ElapsedMilliseconds / 1000) + "";

            return finialValue;

        }



        /// <summary>
        /// 傳統的同步方式,程序執行時間疊加,這里為20秒,
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnTongbu_Click(object sender, EventArgs e)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
          

            int countValue = 0;
            int finialValue = 0;

            int value1 = Calc(1000);
            //這段代碼體現出winForm是單線程的,我們期望會在執行10秒后,界面上先出現如下提示,在實際執行的時候發現,
            //會與最終計算結果....的文本值一起出現在richTextBox1上,
            //雖然 Calc(1000)的值計算出來了,但是線程很忙,緊接着在執行下一段代碼,沒有空去更新richTextBox1控件
            
            this.richTextBox1.Text = "第一階段值:" + value1.ToString();
            for (int i = 0; i < 1000; i++)
            {
                System.Threading.Thread.Sleep(10);
                countValue += i;
            }
            finialValue = value1 + countValue;
            sw.Stop();
            this.richTextBox1.Text += "最終計算結果:" + finialValue + "同步方法耗時:" + (sw.ElapsedMilliseconds / 1000) + "";
        }


        private int Calc(int maxNum)
        {
            int sumValue = 0;
            for (int i = 0; i < maxNum; i++)
            {
                System.Threading.Thread.Sleep(10);
                sumValue += i;
            }
            return sumValue;

        }

      
        private static string GetCalc()
        {
            //Thread.Sleep(10000);
            int a = 1000;
            double b = 0;
            for (int i = 0; i < a; i++)
            {
                System.Threading.Thread.Sleep(10);
                b += i;
            }
            return b.ToString();
        }
        /// <summary>
        ///  Task.Factory.StartNew 程序執行時間20秒
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void button1_Click(object sender, EventArgs e)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            int countValue = 0;
            Task<int> result = Task.Factory.StartNew<int>(() => { return Calc(1000); }).ContinueWith(ts =>
                {
                    for (int i = 0; i < 1000; i++)
                    {
                        System.Threading.Thread.Sleep(10);
                        countValue += i;
                    }
                    return countValue + ts.Result;

                });
            // Task.WaitAll(result);
            await result;

            sw.Stop();
            this.richTextBox1.Text = "最終計算結果:" + result.Result + "異步方法耗時:" + (sw.ElapsedMilliseconds / 1000) + "";
        }
        /// <summary>
        /// 委托的異步調用,界面不能點擊,程序執行時間10S
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async  void button2_Click(object sender, EventArgs e)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            Func<int, int> Func = Calc;
            IAsyncResult AsyncResult = Func.BeginInvoke(1000, null, null);
            int finialValue = 0;
            int countValue = 0;
            Func<int> Func2 = (() =>
            {

                for (int i = 0; i < 1000; i++)
                {
                    System.Threading.Thread.Sleep(10);
                    countValue += i;
                }
                return countValue;

            });

            IAsyncResult AsyncResult2 = Func2.BeginInvoke(null, null);

            int value1 = Func.EndInvoke(AsyncResult);
            int value2 = Func2.EndInvoke(AsyncResult2);

            finialValue = value1 + value2;

            sw.Stop();
            this.richTextBox1.Text = "最終計算結果:" + finialValue + "BeginInvoke異步方法耗時:" + (sw.ElapsedMilliseconds / 1000) + "";
        }
       

    }
}
Async/await Task
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class frmBackgroundworker : Form
    {


        BackgroundWorker bgWorker = new BackgroundWorker();


        public frmBackgroundworker()
        {
            InitializeComponent();
            bgWorker.WorkerReportsProgress = true;
            bgWorker.WorkerSupportsCancellation = true;

            bgWorker.DoWork += bgWorker_DoWork;
            bgWorker.RunWorkerCompleted += bgWorker_RunWorkerCompleted;
            bgWorker.ProgressChanged += bgWorker_ProgressChanged;

        }



        void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)
            {
                this.lblInfo.Text = "用戶已取消";
                return;
            }
            if (e.Error != null)
            {
                this.lblInfo.Text = e.Error.Message;
                return;
            }
            this.lblInfo.Text = e.Result.ToString();

        }

        void bgWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker bw = sender as BackgroundWorker;

            for (int i = 1; i <= 100; i++)
            {
                if (bw.CancellationPending)
                {
                    e.Cancel = true;
                    return;
                }
                System.Threading.Thread.Sleep(20);
                bw.ReportProgress(i, string.Format("當前完成進度{0}%", i));
            }
            System.Threading.Thread.Sleep(1000);
            e.Result = "執行完成";

        }

        void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            this.progressBar1.Value = e.ProgressPercentage;
            this.lblInfo.Text = e.UserState.ToString();

        }

        private void btn_Start_Click(object sender, EventArgs e)
        {
            try
            {
                bgWorker.RunWorkerAsync();
            }
            catch (Exception ex)
            {


            }
        }

        private void btn_Cancel_Click(object sender, EventArgs e)
        {
            try
            {
           
                bgWorker.CancelAsync();
            }
            catch (Exception)
            {

                throw;
            }
        }

       
    }
}
BackgroundWorker刷新進度條


免責聲明!

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



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