多线程---委托实现异步(一)
一、什么是进程?
启动一个程序就是一个进程,也就是说,一个程序就是一个进程。
二、什么是线程?
线程是进程的基本单元。一个进程至少包含一个线程。
三、线程分类:线程分前台线程和后台线程
1..前台线程:只有所有的前台线程都关闭了,程序就完全关闭了。(Thread默认是前台线程,启动后必须计算完才会退出,IsBackground=true; 设置为后台线程,会立即退出)
2.后台线程:只有所有的前台线程关闭了,后台线程会自动关闭。
四、什么是同步?
同步就是执行一段程序,从上到下按顺序依次执行。如果其中有某个方法执行时间较长,那么必须等这个方法执行完毕,才能往下执行。比如:吃饭,到饭点了,我叫小明去吃饭,但是小明说忙完了再去,然后我再哪里等他忙完了,再去吃饭。
五、什么是异步?
异步就是请求一个方法,如果执行时间较长,不管它等待执行的结果,而是继续往下执行,异步会有一个回调函数,把这个方法执行完成的状态返回回去。比如:吃饭,到饭点了,我叫小明去吃饭,但是小明说忙完了再去,然后我不等他了,直接去吃饭了。
六、什么是多线程?
一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说单个程序并发执行多个线程来完成任务。
1.CPU运行速度太快,硬件处理速度跟不上,所有操作系统会进行时间分片管理。这样在宏观的角度来说是多线程并发,看起来统一时刻执行了不同的操作。但是从微观的角度来讲,同一时刻只能有一个线程在处理
2.现在电脑基本上都是多核CPU的,一个CPU在同一个时刻只能运行一个线程,但是多核的CPU在同一时刻就可以运行多个线程。
七、为什么要使用多线程?
1.多个CPU的核可以并行工作,
2.CPU分片,1S能处理1000份任务
八、同步方法和异步方法的区别
1.同步方法卡界面,主线程在忙,不空闲,异步方法不卡界面,主线程闲置,执行任务交给了子线程
2.同步方法执行慢,只有一个线程在执行,异步方法执行快,多个线程并发执行,多线程是资源换性能,有损资源调度
3.同步方法有序执行,异步多线程无序执行
///同步方法
public void SycnMethod() { Console.WriteLine("SycnMethod 方法开始执行...."); Action<string> action = Todo; for (int i = 0; i < 5; i++) { string name = $"AsycnMethod_{i}"; action.Invoke("SycnMethod"); } action.Invoke("SycnMethod"); Console.WriteLine($"SycnMethod方法,ManagedThreadId:{Thread.CurrentThread.ManagedThreadId}"); Console.WriteLine("SycnMethod 方法结束执行...."); }
///异步方法
public void AsycnMethod() { Console.WriteLine("AsycnMethod 方法开始执行...."); Action<string> action = Todo; //action.BeginInvoke("AsycnMethod", s => //{ // Console.WriteLine("回调函数....."); // Console.WriteLine(s.AsyncState); //}, "小明"); for (int i = 0; i < 5; i++) { string name = $"AsycnMethod_{i}"; action.BeginInvoke(name, null, null); } Console.WriteLine($"AsycnMethod方法,ManagedThreadId:{Thread.CurrentThread.ManagedThreadId}"); Console.WriteLine("AsycnMethod 方法结束执行...."); }
九、回调函数(AsyncCallback):委托调用完方法后,将后续动作通过回调参数传进去,子线程完成计算后,去调用回调委托。原理:委托在调用BeginInvoke方法后会返回一个结果为:IAsyncResult 对象,并且把这个对象作为参数传入回调函数AsyncCallback中
1,获取回调函数的参数值:IAsyncResult.AsyncState
2.IsCompleted 等待会卡界面,可以一边等待一边提示
3.WaitOne 即时等待,限时等待
4.EndInvoke 即时等待 等待某次异步调用结束
public void AsyncCallBackMethod() { Console.WriteLine($"AsyncCallBackMethod 方法开始执行,ManagedThreadId:{Thread.CurrentThread.ManagedThreadId}"); Action<string> action = Todo; //AsyncCallback 带一个参数的委托 //回调:将后续动作通过回调参数传进去,子线程完成计算后,去调用回调委托 //action.BeginInvoke 执行的时候返回一个结果为IAsyncResult,并且把这个对象作为参数传入回调函数AsyncCallback中 //获取回调函数的参数值:s.AsyncState IAsyncResult asyncResult = null; AsyncCallback asyncCallback = s => { Console.WriteLine($"{object.ReferenceEquals(s, asyncResult)}");//true Console.WriteLine($"{s.AsyncState}");//name Console.WriteLine($"执行成功了....ManagedThreadId:{Thread.CurrentThread.ManagedThreadId}"); }; asyncResult = action.BeginInvoke("AsyncCallBackMethod", asyncCallback, "names"); //IsCompleted 等待会卡界面,可以一边等待一边提示 int i = 0; while (!asyncResult.IsCompleted) { Thread.Sleep(40); Console.WriteLine($"i={i}"); if (i == 100) { Console.WriteLine("完成100%了"); break; } else { i++; } } Console.WriteLine("已执行完成"); //WaitOne 即时等待,限时等待 asyncResult.AsyncWaitHandle.WaitOne(); //直接等待任务完成 asyncResult.AsyncWaitHandle.WaitOne(-1); //millisecondsTimeout=-1 一直等待任务完成 //EndInvoke 即时等待 等待某次异步调用结束 action.EndInvoke(asyncResult); asyncResult.AsyncWaitHandle.WaitOne(300); //millisecondsTimeout=300 超过300毫秒就不等待了 Console.WriteLine($"AsycnMethod方法,ManagedThreadId:{Thread.CurrentThread.ManagedThreadId}"); Console.WriteLine($"AsycnMethod 方法结束执行,{Thread.CurrentThread.ManagedThreadId}"); }
十、异步方法获取返回结果。委托调用异步方法执行后,将异步方法返回的对象作为参数传入EndInvoke方法中,获取委托执行方法中的返回值。
public void AsyncEndInvoke() { Func<int> func = () => { return DateTime.Now.Hour; }; IAsyncResult asyncResult = func.BeginInvoke(s => { }, null); int result = func.EndInvoke(asyncResult); Console.WriteLine(result); }
private void Todo(string name) { Console.WriteLine($"Todo 方法开始执行...."); long result = 0; for (int i = 0; i < 100000; i++) { result += i; } Thread.Sleep(500); Console.WriteLine($"Todo方法执行的结果:{result},名称{name},ManagedThreadId:{Thread.CurrentThread.ManagedThreadId}"); Console.WriteLine($"Todo 方法结束执行...."); }