使用异步的好处是什么呢?
我认为有如下好处:
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) + "秒"; } } }
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; } } } }