net 多线程
概念
进程:计算机概念,程序运行在服务器占据的全部计算机的资源
线程:计算机概念,是进程在相应操作时候的一个最小单元,也包括cpu/硬盘/内存 虚拟概念
进程和线程:包含关系,线程是属于某一个进程的,如果一个进程销毁,线程也就不会存在。
句柄:描述程序中的某一个最小单元,是一个long数字,操作系统通过这个数字识别应用程序。,一个程序 的ID,或者说一个控件的ID
多线程:计算概念,就是某一个进程中,多个线程同时运行;
C#中的多线程:
Thread类是C#语言对线程对象一个封装;
为什么可以多线程呢?
1、CPU有多个核;可以并行计算;
双核四线:这里的线程是模拟核;
2、cpu分片:某1s的处理能切分成1000份,操作系统调度去相应不同的任务;
从宏观角度来说:感觉就有多个任务在并发执行;
从微观角度来说:一个物理cpu不能在某一刻为某一个任务服务
同步异步:
同步方法:发起调用,只有在调用的方法完成以后,才能继续执行一下一行代码,按照顺序执行;
诚心请吃饭,我请你吃饭,你说你现在需要忙一会儿,我等你,等你忙完了以后,咱们一起去吃饭。
异步方法:发起调用,不等待完成,直接进入下一行代码的执行,启动一个新的线程来完成计算
客气一下请人吃饭:我请你吃饭,你说你现在需要忙一会儿,我就不等你了,我自己先去吃饭了,你忙完以后,自己去吃饭。
1、同步方法卡界面:主线线程(UI线程)忙于计算,无暇他顾
异步方法不卡界面:因为异步方法是新启动一个线程去完后计算,主线程闲置
改善用户体验,winform程序点击某一个按钮,不会卡死界面;
发短信,发邮件可以交给一个子线程去完成
2、同步方法执行慢:只有一个线程完成计算
异步方法执行快:多个线程去完成计算
10000ms 3000ms 快了三倍多
20000ms 15000ms cpu密集型计算
资源换性能
3、同步方法有序执行,异步多线程无顺序
启动无序,线程资源是向操作系统申请的,操作系统有自己的调度策略,所以启动是随机的;
以上两点得出: 结束也是没有顺序
/如果需要控制顺序呢?怎么实现?
回调:把后续的动作通过回调参数传递进去,子线程完成计算以后,去嗲用这个回调委托
一、Thread
Thread.CurrentThread.ManagedThreadId.ToString("00") ; //当前线程id
Thread.Sleep(2000);//线程等待
二、委托
委托可以理解为一种协议。委托,是什么意思呢?举个例子,你碰到一件事,你需要让别人来帮你做(可能你还有别的事情要做),这就是委托,把你现在不能做的事让别人去做。为什么说委托就像一个协议呢,因为你不想把事情搞砸了,所以你“委托”的这个人做的这件事,你需要给他定一个标准。在C#中就是给所委托的对象定义好签名,参数有几个,分别是什么类型,委托方法需要反馈给你什么东西(或者不反馈)。
C#的委托调用有以下2种方法:
1、BeinInvoke => 异步调用,EndInvoke => 获得异步调用的返回值(方法没执行完毕之前会一直阻塞);
在C#中,任何涉及BeginXXX与EndXXX名字的方法都是异步。
2、Invoke => 同步调用;
在Control中用以上2种方法都会造成界面假死,因为这是UI线程。
我们知道 beginvoke就是通过线程的调用来异步的完成一些工作。一般只需要启动它就好,让它一直操作着。例如 用begininvoke修改界面显示,那么就是每次有所变化时它自动的改变界面的显示,因为它在后台执行着。
但是有时候我们需要知道它的结束信息,并且在结束时还有所安排。这时候就需要endinvoke了
C#如何使用异步编程【BeginInvoke/EndInvoke】
1、Action 委托
- Action委托至少0个参数,至多16个参数,无返回值。
- Action 表示无参,无返回值的委托。
- Action<int,string> 表示有传入参数int,string无返回值的委托。
- Action<int,string,bool> 表示有传入参数int,string,bool无返回值的委托。
- Action<int,int,int,int> 表示有传入4个int型参数,无返回值的委托。
IAsyncResult asyncResult = null; AsyncCallback callback = ar => { Thread.Sleep(5000); Console.WriteLine($"这里是beginInvoke的第三个参数{ar.AsyncState}"); Console.WriteLine(object.ReferenceEquals(ar, asyncResult)); Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy - MM - dd HH: mm:ss.fff")}"); Console.WriteLine("计算结束"); }; { //1、回调 Action<string> action = this.DoSomethingLong; //如果把自定义的参数传入到回调函数中去? asyncResult = action.BeginInvoke("btnAsyncAdvanced_Click", callback, "八万公里"); Console.WriteLine("计算结束"); } //几种等待 //2、IsCompleted 完成等待 { int i = 0; while (!asyncResult.IsCompleted) { if (i < 9) { Console.WriteLine($"正在玩命为你加载中。。。已经完成{++i * 10}%"); } else { Console.WriteLine($"正在玩命为你加载中。。。已经完成99.9999%"); } Thread.Sleep(200); } Console.WriteLine("加载完成。。。"); } //以上两种都是为了等待任务的完成; //3、WaitOne等待 asyncResult.AsyncWaitHandle.WaitOne();//一直等待任务完成 asyncResult.AsyncWaitHandle.WaitOne(-1);//一直等待任务完成 asyncResult.AsyncWaitHandle.WaitOne(3000);//最多等待3000ms,如果超时了,就不等待了 { //4、EndInvoke也可以等待,可以获取委托返回值 Func<int> func = () => { //Thread.Sleep(5000); return DateTime.Now.Year; }; func.Invoke(); IAsyncResult asyncResult1 = func.BeginInvoke(ar => { func.EndInvoke(ar); }, null); int iResult = func.EndInvoke(asyncResult1); Console.WriteLine(iResult); }
技巧
c# Task返回值
Task返回值,目前有2种情况,一种是异步async返回值,一种是同步返回值
第一种:异步返回值
Task方法如果加了async关键字,那么就是异步返回方法,如果是异步返回方法,需要返回一个值时,直接return value,就可以了。
第二种:同步返回值
Task方法如果没有加async关键字,需要返回一个值时,使用Task.FromResult方法,Task.FromResult(value)就可以了。