进程-线程-多线程,同步和异步
1.什么是进程?
当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源。
而一个进程又是由多个线程所组成的。
2.什么是线程?
线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的,即不同的线程可以执行同样的函数。
3.什么是多线程?
多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。
4.多线程的好处:
可以提高CPU的利用率。在多线程程序中,一个线程必须等待的时候,CPU可以运行其它的线程而不是等待,这样就大大提高了程序的效率。
5.多线程的不利方面:
线程也是程序,所以线程需要占用内存,线程越多占用内存也越多;
多线程需要协调和管理,所以需要CPU时间跟踪线程;
线程之间对共享资源的访问会相互影响,必须解决竞用共享资源的问题;
线程太多会导致控制太复杂,最终可能造成很多Bug

1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Linq; 7 using System.Text; 8 using System.Threading; 9 using System.Threading.Tasks; 10 using System.Windows.Forms; 11 12 namespace MyAsyncThread 13 { 14 /// <summary> 15 /// 1 进程-线程-多线程,同步和异步 16 /// 2 委托启动异步调用 17 /// 3 多线程特点:不卡主线程、速度快、无序性 18 /// 4 异步的回调和状态参数 19 /// 5 异步等待三种方式 20 /// 6 异步返回值 21 /// 多线程是.Net开发非常重要的一块儿, 22 /// 但是很多开发者工作多年,对多线程几乎不用/很畏惧/不明所以,写代码的时候没有考虑多线程的场景 23 /// 24 /// 25 /// 进程:计算机概念,程序在服务器运行时占据全部计算资源综总和 26 /// 虚拟的, 27 /// 线程:计算机概念,进程在响应操作时最小单位,也包含CPU 内存 网络 硬盘IO 28 /// 虚拟的概念,更加看不见摸不着 29 /// 一个进程会包含多个线程;线程隶属于某个进程,进程销毁线程也就没了 30 /// 句柄:其实是个long数字,是操作系统标识应用程序 31 /// 多线程:计算机概念,一个进程有多个线程同时运行 32 /// 33 /// C#里面的多线程: 34 /// Thread类是C#语言对线程对象的一个封装 35 /// 36 /// 为什么可以多线程呢? 37 /// 1 多个CPU的核可以并行工作, 38 /// 4核8线程,这里的线程指的是模拟核 39 /// 40 /// 2 CPU分片,1s的处理能力分成1000份,操作系统调度着去响应不同的任务 41 /// 从宏观角度来说,感觉就是多个任务在并发执行 42 /// 从微观角度来说,一个物理cpu同一时刻只能为一个任务服务 43 /// 44 /// 并行:多核之间叫并行 45 /// 并发:CPU分片的并发 46 /// 47 /// 同步异步: 48 /// 同步方法:发起调用,完成后才继续下一行;非常符合开发思维,有序执行; 49 /// 诚心诚意的请人吃饭,邀请Nick,Nick要忙一会儿,等着Nick完成后,再一起去吃饭 50 /// 异步方法:发起调用,不等待完成,直接进入下一行,启动一个新线程来完成方法的计算 51 /// 客气一下的请人吃饭,邀请亡五,亡五要忙一会儿,你忙着我去吃饭了,你忙完自己去吃饭吧 52 /// </summary> 53 public partial class frmThreads : Form 54 { 55 public frmThreads() 56 { 57 //Thread 58 InitializeComponent(); 59 Console.WriteLine("欢迎来到.net高级班vip课程,今天是Eleven老师带来的异步多线程内容"); 60 } 61 62 #region Sync 63 /// <summary> 64 /// 同步方法 65 /// </summary> 66 /// <param name="sender"></param> 67 /// <param name="e"></param> 68 private void btnSync_Click(object sender, EventArgs e) 69 { 70 Console.WriteLine($"****************btnSync_Click Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************"); 71 int l = 3; 72 int m = 4; 73 int n = l + m; 74 for (int i = 0; i < 5; i++) 75 { 76 string name = string.Format($"btnSync_Click_{i}"); 77 this.DoSomethingLong(name); 78 } 79 Console.WriteLine($"****************btnSync_Click End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************"); 80 81 } 82 #endregion 83 84 #region Async 85 /// <summary> 86 /// 异步方法 87 /// 1 同步方法卡界面:主线程(UI线程)忙于计算,无暇他顾 88 /// 异步多线程方法不卡界面:主线程闲置,计算任务交给子线程完成 89 /// 改善用户体验,winform点击个按钮不至于卡死; 90 /// web应用发个短信通知,异步多线程去发短信; 91 /// 92 /// 2 同步方法慢,只有一个线程计算 93 /// 异步多线程方法快,因为5个线程并发计算 94 /// 12658ms 3636ms 不到4倍 CPU密集型计算(资源受限) 95 /// 10126ms 2075ms 差不多5倍,也不到5倍,Sleep(资源够用) 96 /// 多线程其实是资源换性能,1 资源不是无限的 2 资源调度损耗 97 /// 98 /// 一个订单表统计很耗时间,能不能多线程优化下性能? 不能!这就是一个操作,没法并行 99 /// 需要查询数据库/调用接口/读硬盘文件/做数据计算,能不能多线程优化下性能? 可以,多个任务可以并行 100 /// 线程不是越多越好,因为资源有限,而且调用有损耗 101 /// 102 /// 3 同步方法有序进行,异步多线程无序 103 /// 启动无序:线程资源是向操作系统申请的,由操作系统的调度策略决定,所以启动顺序随机 104 /// 同一个任务同一个线程,执行时间也不确定,CPU分片 105 /// 以上相加,结束也无序 106 /// 使用多线程请一定小心,很多事儿不是相当然的,尤其是多线程操作间有顺序要求的时候, 107 /// 通过延迟一点启动来控制顺序?或者预计下结束顺序? 这些都不靠谱! 108 /// 109 /// 需要控制顺序,晚点分解! 110 /// </summary> 111 /// <param name="sender"></param> 112 /// <param name="e"></param> 113 private void btnAsync_Click(object sender, EventArgs e) 114 { 115 Console.WriteLine($"****************btnAsync_Click Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************"); 116 Action<string> action = this.DoSomethingLong; 117 118 //action.Invoke("btnAsync_Click_1"); 119 //action("btnAsync_Click_1"); 120 121 //委托自身需要的参数+2个异步参数 122 //action.BeginInvoke("btnAsync_Click_1", null, null); 123 124 for (int i = 0; i < 5; i++) 125 { 126 string name = string.Format($"btnAsync_Click_{i}"); 127 action.BeginInvoke(name, null, null); 128 } 129 130 Console.WriteLine($"****************btnAsync_Click End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************"); 131 } 132 #endregion 133 134 135 #region Private Method 136 /// <summary> 137 /// 一个比较耗时耗资源的私有方法 138 /// </summary> 139 /// <param name="name"></param> 140 private void DoSomethingLong(string name) 141 { 142 Console.WriteLine($"****************DoSomethingLong Start {name} {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************"); 143 long lResult = 0; 144 for (int i = 0; i < 1_000_000_000; i++) 145 { 146 lResult += i; 147 } 148 //Thread.Sleep(2000); 149 150 Console.WriteLine($"****************DoSomethingLong End {name} {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} {lResult}***************"); 151 } 152 #endregion 153 154 #region btnAsyncAdvanced_Click 155 private void btnAsyncAdvanced_Click(object sender, EventArgs e) 156 { 157 Console.WriteLine($"****************btnAsync_Click Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************"); 158 159 //Action<string> action = this.DoSomethingLong; 160 161 ////1 回调:将后续动作通过回调参数传递进去,子线程完成计算后,去调用这个回调委托 162 //IAsyncResult asyncResult = null;//是对异步调用操作的描述 163 //AsyncCallback callback = ar => 164 //{ 165 // Console.WriteLine($"{object.ReferenceEquals(ar, asyncResult)}"); 166 // Console.WriteLine($"btnAsyncAdvanced_Click计算成功了。{ar.AsyncState}。{Thread.CurrentThread.ManagedThreadId.ToString("00")}"); 167 //}; 168 //asyncResult = action.BeginInvoke("btnAsyncAdvanced_Click", callback, "花生"); 169 170 //////2 通过IsComplate等待,卡界面--主线程在等待,边等待边提示 171 //////( Thread.Sleep(200);位置变了,少了一句99.9999) 172 ////int i = 0; 173 ////while (!asyncResult.IsCompleted) 174 ////{ 175 //// if (i < 9) 176 //// { 177 //// Console.WriteLine($"中华民族复兴完成{++i * 10}%...."); 178 //// } 179 //// else 180 //// { 181 //// Console.WriteLine($"中华民族复兴完成99.999999%...."); 182 //// } 183 //// Thread.Sleep(200); 184 ////} 185 ////Console.WriteLine("中华民族复兴已完成,沉睡的东方雄狮已觉醒!"); 186 187 ////3 WaitOne等待,即时等待 限时等待 188 ////asyncResult.AsyncWaitHandle.WaitOne();//直接等待任务完成 189 ////asyncResult.AsyncWaitHandle.WaitOne(-1);//一直等待任务完成 190 ////asyncResult.AsyncWaitHandle.WaitOne(1000);//最多等待1000ms,超时就不等了 191 192 ////4 EndInvoke 即时等待,而且可以获取委托的返回值 一个异步操作只能End一次 193 ////action.EndInvoke(asyncResult);//等待某次异步调用操作结束 194 195 ////Console.WriteLine("全部计算成功了。。"); 196 197 Func<int> func = () => 198 { 199 Thread.Sleep(2000); 200 return DateTime.Now.Hour; 201 }; 202 int iResult = func.Invoke();//22 203 IAsyncResult asyncResult = func.BeginInvoke(ar => 204 { 205 //int iEndResultIn = func.EndInvoke(ar); 206 }, null); 207 int iEndResult = func.EndInvoke(asyncResult);//22 208 209 Console.WriteLine($"****************btnAsync_Click End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************"); 210 } 211 #endregion 212 } 213 }