同步方法
1 Console.WriteLine($"****************Sync Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************"); 2 Action<string> action = this.DoSomething; 3 for (int i = 0; i < 5; i++) 4 { 5 string name = string.Format($"Sync_{i}"); 6 action.Invoke(name); //等价 方法直接执行 this.DoSomething(name); 7 } 8 Console.WriteLine($"****************Sync End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
异步方法
1 Console.WriteLine($"****************Async Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************"); 2 for (int i = 0; i < 5; i++) 3 { 4 var name = $"Async_{i}"; 5 action.BeginInvoke(name,null,null); 6 } 7 Console.WriteLine($"****************Async End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
1 /// <summary> 2 /// 一个比较耗时耗资源的私有方法 3 /// </summary> 4 private void DoSomething(string name) 5 { 6 Console.WriteLine($"****************{name} Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************"); 7 long lResult = 0; 8 for (int i = 0; i < 1_000_000; i++) 9 { 10 lResult += i; 11 } 12 Thread.Sleep(2000); 13 Console.WriteLine($"****************{name} Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************"); 14 }
运行上面的代码,我们发现几个问题:
1、同步方法卡界面:主线程(UI线程)忙于计算,无暇他顾 ;异步多线程方法不卡界面:主线程闲置,计算任务交给子线程完成
2、同步方法慢,只有一个线程计算;
异步多线程方法快,因为5个线程并发计算 差不多5倍,也不到5倍,CPU密集型计算(资源受限)
多线程其实是资源换性能,1 资源不是无限的 2 资源调度损耗
3、同步方法有序进行;
异步多线程无序
启动无序:线程资源是向操作系统申请的,由操作系统的调度策略决定,所以启动顺序随机
执行时间无序:同一个任务同一个线程,执行时间也不确定,CPU分片
结束无序:以上相加,结束也无序
AsyncCallback 异步回调:将后续动作通过回调参数传递进去,子线程完成计算后,去调用这个回调委托
AsyncState 用户定义对象:可以作为回调的参数
1 Console.WriteLine($"****************Async Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************"); 2 AsyncCallback callback = ar => Console.WriteLine($"{nameof(AsyncCallback)} 是否完成:{ar.IsCompleted} 用户定义对象:{ar.AsyncState} {Thread.CurrentThread.ManagedThreadId.ToString("00")}"); 3 for (int i = 0; i < 5; i++) 4 { 5 var name = $"Async_{i}"; 6 action.BeginInvoke(name, callback, i); 7 } 8 Console.WriteLine($"****************Async End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
IAsyncResult 对异步调用操作的描述
IsCompleted 判定异步任务是否完成
while (!asyncResult.IsCompleted) //if(!asyncResult.IsCompleted)
{
// Do SomeThing
}
WaitOne 等待,即时等待 限时等待
asyncResult.AsyncWaitHandle.WaitOne();//直接等待任务完成
asyncResult.AsyncWaitHandle.WaitOne(-1);//一直等待任务完成
asyncResult.AsyncWaitHandle.WaitOne(1000);//最多等待1000ms,超时就不等了
EndInvoke 即时等待,而且可以获取委托的返回值 一个异步操作只能End一次
1 Func<int, int> func = Sum; 2 func.BeginInvoke(10, ar => { 3 Console.WriteLine($"线程ID:{ Thread.CurrentThread.ManagedThreadId.ToString("00")} 计算结果:{func.EndInvoke(ar)}"); 4 }, null); 5 6 7 IAsyncResult asyncResult = func.BeginInvoke(5,ar => 8 { 9 //int iEndResultIn = func.EndInvoke(ar); 10 }, null); 11 int iEndResult = func.EndInvoke(asyncResult);
EndInvoke 可以写在BeginInvoke里也可以写在外面 但只能写一次 否则会报错
微软文档:
IAsyncResult:https://docs.microsoft.com/zh-cn/dotnet/api/system.iasyncresult?view=netframework-4.8
AsyncCallback:https://docs.microsoft.com/zh-cn/dotnet/api/system.asynccallback?view=netframework-4.8