多线程Task(thread ,threadpool 已经过时)
一、进程:计算机概念,虚拟的记录, 描述一个应用程序在计算机上运行的时候,所消耗的各种资源的集合---Cpu+内容+磁盘IO+网络资源;
二、线程:(计算机资源)一个程序的进程中,所执行的具体的某一个动作的最小执行流;小到点击某个按钮,大到通过网络发送一句话出去;
具体到某一个人:
进程必然是包含了多个线程;线程是依附于进程存在的;如果进程不在了,线程也随之消失了;
三、句柄:是一个long了类型的数字,对应这计算机程序中的某一个小部件;要操作程序,对应的最小的单位;
公司中的任何一个物件 --编号--计算机---会给计算机坐个编号---(部门---座位号) ====资产处的人员和设备对应表
四、为什么计算机可以多线程?跟计算机的CPU的核数有关;
6核12线程:把六个核心进行逻辑切分:如果有动作需要计算机响应,操作系统就会去申请CPU来处理;CPU在执行动作的时候,CPU是分片执行:
分片:把每一个核每一毫秒可以执行的动作,切分成10000份;操作系统在调度的时候,执行动作,切分后去执行的多个动作的时候;开始动作A,使用的是分片后的某一份; 结束的时候,可能使用的是另外的某一份;
计算机在不断的调度过程中;
1.从宏观角度来说:多个动作,就可以做到在某一段时间内;看似同时执行完毕了;
2.从微观的角度来说:某一时刻,同意时刻只能处理一件事儿--串行执行;
同步方法:
单线程执行代码命令:同步执行;
线性执行,从上往下依次执行--很符合我们人类的思维逻辑,线程ID为01(主线程/UI线程) 同步方法执行慢;卡顿界面--只有一个线程参与计算
异步方法:
多线程执行代码命令:异步执行:
开启了一个新的线程(多线程--子线程)(有一个新的线程Id);且不再是线型执行了; UI线程不等待子线程执行完毕;主线程直接往后执行; 子线程延迟执行
异步方法执行快:不卡顿界面;开启了一个新的线程去执行去了;开启了五个线程去执行动作:消耗的计算机资源多(工钱多)
异步方法--多线程方法--以资源换时间; 使用大量的资源,降低时间成本;
无序执行:线程开启无法控制谁先谁后;线程执行计算结束也无法控制谁先谁后;---多线程异步执行:无序执行;
//在ASP.NET Core的年代:BeginInvoke不再支持了 Action<string> action = this.DoSomething; AsyncCallback asyncCallback = null; action.BeginInvoke(" Seven ", asyncCallback, "Object");
Task.Run(() => { DoSomething("kulala"); });
线程开启的方式
三种 new Task Task.Run() Task.Factory Parallel
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | Task task = <strong> new Task</strong>( new Action(() => { Debug.WriteLine( "Task学习" ); this .DoSomething( "Seven" ); })); task.Start(); //线程开启了 Task.<strong>Run</strong>(() => { this .DoSomething( "Seven" ); }); <strong>TaskFactory</strong> factory = Task.Factory; factory.StartNew(() => { this .DoSomething( "一意" ); }); |
List<Action> acitonList = new List<Action>();
acitonList.Add(() => { });
acitonList.Add(() => { });
acitonList.Add(() => { });
Parallel.Invoke(acitonList.ToArray());//也是可以开启线程,可以一次放入很多个委托去执行;
Parallel
//1.可以传入多个委托
//2.多个委托中的内容是会开启线程来执行---执行这里的线程有可能是新的线程,也有可能是主线程参与计算的
//3.会阻塞主线程---相当于是主线程等待子线程执行结束
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | { List<Action> acitonList = new List<Action>(); acitonList.Add(() => { }); acitonList.Add(() => { }); acitonList.Add(() => { }); Parallel.Invoke(acitonList.ToArray()); //也是可以开启线程,可以一次放入很多个委托去执行; } ParallelOptions options = new ParallelOptions(); options.MaxDegreeOfParallelism = 3; Parallel.Invoke(options, () => { Debug.WriteLine($ "线程ID: {Thread.CurrentThread.ManagedThreadId.ToString(" 00 ")}" ); this .DoSomething( "this is Action 01" ); }, () => { Debug.WriteLine($ "线程ID: {Thread.CurrentThread.ManagedThreadId.ToString(" 00 ")}" ); this .DoSomething( "this is Action 02" ); }, () => { Debug.WriteLine($ "线程ID: {Thread.CurrentThread.ManagedThreadId.ToString(" 00 ")}" ); this .DoSomething( "this is Action 03" ); });能不能不阻塞界面?<strong>包一个Task 相当于给一个父线程,父线程不参与计算</strong> { Task.Run(() => { Parallel.Invoke( () => { Debug.WriteLine($ "线程ID: {Thread.CurrentThread.ManagedThreadId.ToString(" 00 ")}" ); this .DoSomething( "this is Action 01" ); }, () => { Debug.WriteLine($ "线程ID: {Thread.CurrentThread.ManagedThreadId.ToString(" 00 ")}" ); this .DoSomething( "this is Action 02" ); }, () => { Debug.WriteLine($ "线程ID: {Thread.CurrentThread.ManagedThreadId.ToString(" 00 ")}" ); this .DoSomething( "this is Action 03" ); }); }); }<br><strong>--Parallel是基于Task一个封装;<br>开启多个线程--Parallel.For Foreach</strong><strong>控制线程的数量-- - Parallel就是可以控制线程的数量,不至于出现线程泛滥的情况</strong> { //方式1 ParallelOptions options = new ParallelOptions(); options.MaxDegreeOfParallelism = 3; Parallel.For(0, <strong>10</strong>, options, index => { Debug.WriteLine($ "index:{ index} 线程ID: {Thread.CurrentThread.ManagedThreadId.ToString(" 00 ")}" ); this .DoSomething( "this is Action 03" ); }); } { //方式2<br> List<int> intlist = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }; //100个 100个任务: 如果我使用Parallel来开启线程计算;线程会有100个线程来执行--线程数量会过多; 最好能够控制线程数量 100个任务; 限定开启5个线程;控制反正一共就只有五个线程参与计算 相当于5个线程去平摊这100个任务---既开启了多个线程来执行任务---提高性能---且没有过多的开启线程(过多的开启线程会过多的损耗计算机的资源); ParallelOptions options = new ParallelOptions(); options.MaxDegreeOfParallelism = 3; //会有17个任务,限定了3个线程去执行这17个任务 Parallel.ForEach(intlist, options, s => { Debug.WriteLine($ "index:{ s} 线程ID: {Thread.CurrentThread.ManagedThreadId.ToString(" 00 ")}" ); this .DoSomething( "this is Action 03" ); });<br>} |
前台线程 后台线程
1 2 3 4 5 | // Thread thread = null; //thread.Abort();//线程停止; //thread.Start(); //thread.IsBackground = true;//后台线程:进程结束,线程随之消失 //thread.IsBackground = false;//前台线程:进程结束,线程把内部需要执行的动作执行完毕,然后消失 |
父子级线程
一个Task内部,开启了几个线程以后;Task内部的线程可以理解为子线程;
父线程在等待的时候,子线程没有线程等待;子线程可能内容还没有执行完毕,父线程就已经结束了; ------父线程只管生不管养
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | Task task = new Task(() => { Debug.WriteLine($ "****************task开始了: {Thread.CurrentThread.ManagedThreadId.ToString(" 00 ")} ***************" ); Task task1 = new Task(() => { Debug.WriteLine($ "****************task1: {Thread.CurrentThread.ManagedThreadId.ToString(" 00 ")} ***************" ); Thread.Sleep(1000); Debug.WriteLine( "我是task1线程" ); }); Task task2 = new Task(() => { Debug.WriteLine($ "****************task2: {Thread.CurrentThread.ManagedThreadId.ToString(" 00 ")} ***************" ); Thread.Sleep(1000); Debug.WriteLine( "我是task2线程" ); }); task1.Start(); task2.Start(); Debug.WriteLine($ "****************task: {Thread.CurrentThread.ManagedThreadId.ToString(" 00 ")} ***************" ); }); task.Start(); //线程启动了 task.Wait(); //单个线程的等待;等待task 内部的内容执行完毕,这里会卡顿界面;是主线程等待; // task.Wait();//等待执行完成: task.Wait(TimeSpan.FromMilliseconds(1100)); task.Wait(1000); //限时等待;过时不候 |
线程优先级
TaskCreationOptions.PreferFairness 相对来说比较公平执行的:如果是先申请的线程,就会优先执行; 可以在源数据中查看
线程等待
Thread.Sleep(3000);//主线程执行到这儿会卡顿等待;等待3000ms后继续往后;
Task.Delay(3000).ContinueWith(t =>
{Debug.WriteLine($"****************Delay || 线程ID: {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
3000ms以后, 不卡顿界面 去执行一段业务逻辑:执行的动作就是ContinueWith内部的委托;ContinueWith内部的执行有可能是一个全新的线程去执行,也有可能是主线程去执行
Task几个主要应用
ContinueWhenAny ContinueWhenAll WaitAny WaitAll
List<Task> taskList = new List<Task>();
TaskFactory factory = new TaskFactory();
taskList.Add(factory.StartNew(obj => Coding("")));
taskList.Add(factory.StartNew(obj => Coding("")));
factory.ContinueWhenAny(taskList.ToArray(), ts =>
{
Debug.WriteLine($"{ts.AsyncState}开发完毕准备环境。。。"); //相当于是一个回调;主线程执行的时候,这里是不卡段界面的;当taskList集合中的某一个线程执行结束语了;就触发后面委托中的动作;---不卡顿界面--用户体验就更好
});
factory.ContinueWhenAll(taskList.ToArray(), ts =>
{
Debug.WriteLine($"所有人开发完毕,我们一起庆祝一下,一起吃个饭!");
});
Task.WaitAny(taskList.ToArray()); ///等待几个线程中的某一个线程执行结束;---主线程会等待-- - 会卡顿界面;一直到某一个线程执行结束后,才往后执行;--体验不好
Task.WaitAll(taskList.ToArray()); //主线程会等待-- 一直到所有的线程执行结束,才往后执行;- 会卡顿界面;--体验不好
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现