ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

测试一次多线程

2022-06-13 11:02:16  阅读:134  来源: 互联网

标签:一次 Console WriteLine Thread tasks Task 线程 测试 多线程


  1 using System;
  2 using System.Collections.Generic;
  3 using System.Diagnostics;
  4 using System.Linq;
  5 using System.Text;
  6 using System.Threading;
  7 using System.Threading.Tasks;
  8 
  9 namespace AsyncTask
 10 {
 11     class Program
 12     {
 13         /*
 14          前台线程和后台线程的区别
 15                  应用程序的主线程以及使用Thread构造的线程都默认为前台线程
 16         使用Thread建立的线程默认情况下是前台线程,在进程中,只要有一个前台线程未退出,进程就不会终止.
 17         主线程就是一个前台线程。而后台线程不管线程是否结束,只要所有的前台线程都退出(包括正常退出和异常退出)后,进程就会自动终止.
 18         一般后台线程用于处理时间较短的任务,如在一个Web服务器中可以利用后台线程来处理客户端发过来的请求信息。而前台线程一般用于处理需要长时间等待的任务,如在Web服务器中的监听客户端请求的程序,或是定时对某些系统资源进行扫描的程序
 19          */
 20 
 21         /*
 22          * 异步和多线程有什么区别
 23          *          https://www.cnblogs.com/gbat/articles/6385182.html
 24          *          这个网址说的还可以
 25          * 
 26          * 
 27          * 
 28          异步多线程:什么时候用多线程?  提升速度==>可以并发运行为前提,不要强行拆分
 29                 例子:一个数据库,多条语句执行,即使拆分开了,还是要一条一条执行;;  监控执行监控的,高空抛物执行高空抛物的
 30                 
 31             场景1:项目经理 制定好 项目计划,  分发任务,   但是项目经理还要和甲方说 可以验收了,
 32                       如果项目经理属于一个线程,  其他人属于一个线程, 那么  
 33                       告知甲方可以验收就会在编码前边
 34                       这怎么搞?
 35 
 36 
 37             whenall  whenany和waitall  waitany
 38             when这一类得如果说是不需要给用户反馈的话,就可以用(比如写个日志,发个邮件啥得)
 39             wait这一类得话,可以是给用户一个反馈得,有些时候必须要阻塞一下
 40 
 41             自己想得:when这一类得话,可以用ContinueWith做回调,  也可以给用户反馈
 42              */
 43 
 44 
 45         //加锁后
 46         //private 防止外边的也去lock   static 全场唯一     readonly  不能改动   object 表示引用
 47         private static readonly object myLock = new Object();//微软官方推荐
 48         static void Main(string[] args)
 49         {
 50             #region  第一部分   Task.Run();
 51             //Console.WriteLine($"项目经理启动了一个项目:==={Thread.CurrentThread.ManagedThreadId.ToString()}===");
 52             //Console.WriteLine($"项目经理分发任务:==={Thread.CurrentThread.ManagedThreadId.ToString()}===");
 53 
 54 
 55             ////创建线程容器,把编码线程放进去,加入阻塞
 56             //List<Task> tasks = new List<Task>();
 57             ////开启新线程
 58             //tasks.Add(Task.Run(() => Console.WriteLine($"夏侯惇*****收到任务开始编程:++++{Thread.CurrentThread.ManagedThreadId.ToString()}++++")));
 59             //tasks.Add(Task.Run(() => Console.WriteLine($"曹仁*****收到任务开始编程:++++{Thread.CurrentThread.ManagedThreadId.ToString()}++++")));
 60             //tasks.Add(Task.Run(() => Console.WriteLine($"张辽*****收到任务开始编程:++++{Thread.CurrentThread.ManagedThreadId.ToString()}++++")));
 61             //tasks.Add(Task.Run(() => Console.WriteLine($"徐晃*****收到任务开始编程:++++{Thread.CurrentThread.ManagedThreadId.ToString()}++++")));
 62 
 63             ////Task.WaitAny(tasks.ToArray());//这里会阻塞线程,等待  =某= 个任务完成后,就会进入下一行  卡界面
 64             ////Console.WriteLine($"这里有奖品,先到先得");
 65             ////Task.WaitAll(tasks.ToArray(),1000);//这里会等待子线程执行一秒钟  ,一秒以后会继续执行,如果一秒内执行完了,OK继续,这里意思是最多等待1秒
 66             ////Console.WriteLine("1秒以后,我会继续执行");
 67 
 68             ///*多线程加快速度  ,但是全部任务完成以后才可以执行下面这个验收    那么主线程(经理线程就要 阻塞一下)*/
 69             //Task.WaitAll(tasks.ToArray());//这里会阻塞当前线程,等着全部任务完成后, 再进行下一行  会卡界面
 70             //Console.WriteLine($"项目经理告知甲方开始验收项目了!!!!!:==={Thread.CurrentThread.ManagedThreadId.ToString()}===");
 71 
 72 
 73             /*如果想要不卡界面怎么整呢
 74                ContinueWith  做一个延续,其实就是个回调函数,  当前面得任务完成后, 直接就做接下来得动作
 75              */
 76             //Task.WhenAny(tasks.ToArray()).ContinueWith(m => Console.WriteLine("用我可以不用等待,不回卡界面,我是某个完成任务,就可以"));
 77             //Task.WhenAll(tasks.ToArray()).ContinueWith(m=>Console.WriteLine("用我可以不用等待,不回卡界面,我是全部执行完的任务"));
 78             #endregion
 79 
 80             #region  第二部分  模拟执行10000个任务,但是只有10个线程
 81             /*
 82              模拟执行10000个任务,但是只有10个线程
 83              
 84              */
 85             //模拟任务数量
 86             //List<int> list = new List<int>();
 87             //for (int i = 0; i < list.Count; i++)
 88             //{
 89             //    list.Add(i);
 90             //}
 91             ////模拟任务
 92             //Action<int> action = i =>
 93             //{
 94             //    Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString());
 95             //    Thread.Sleep(new Random().Next(100,300));
 96             //};
 97 
 98             //List<Task> tasks = new List<Task>();
 99 
100             //foreach (var item in list)
101             //{
102             //    int k = item;
103             //    tasks.Add(Task.Run(()=>action.Invoke(k)));//开启线程任务,并封装近Task集合中
104             //    //判断线程执行数量
105             //    if (tasks.Count>10)//>10说明至少10个了,
106             //    {
107             //        /*
108             //         一旦超过10个线程任务,那就得在这等着,等着玩意有任务完成了,那么就将已经完成得清理掉,进行下一次循环
109             //         */
110             //        Task.WaitAny(tasks.ToArray());//有一个执行完就,就开始下一步
111             //        tasks = tasks.Where(t=>t.Status!=TaskStatus.RanToCompletion).ToList();//将已经完成的进行过滤,
112             //    }
113             //}
114             //Task.WaitAll(tasks.ToArray());
115 
116 
117 
118             #endregion
119 
120             #region  第三部分   Task.Delay  和  Thread.Sleep()  的区别
121             /*
122              * Task.Delay  和  Thread.Sleep()  的区别?
123              Task.Delay不会卡界面,不会让用户等待,可以继续操作, 过一段时间后,才开始反馈信息
124              Thread.Sleep() 会卡界面, 会让用户等待, 不可以继续操作,  只有等睡足了,可开始反馈
125              */
126 
127             Stopwatch stopwatch = new Stopwatch();//计时器
128                                                   //方式1
129                                                   //stopwatch.Start();//开始计时
130                                                   //Thread.Sleep(2000);//睡觉2秒
131                                                   //stopwatch.Stop();
132                                                   //Console.WriteLine(stopwatch.ElapsedMilliseconds);
133 
134             //方式2
135             //Stopwatch stopwatch = new Stopwatch();//计时器
136             //stopwatch.Start();//开始计时
137             //Task.Delay(2000).ContinueWith(t =>
138             //{
139             //    stopwatch.Stop();
140             //    Console.WriteLine(stopwatch.ElapsedMilliseconds);
141             //});
142 
143             //方式3   
144             //stopwatch.Start();//开始计时
145             //Task.Run(()=> {
146             //    Thread.Sleep(2000);//睡觉2秒
147             //    stopwatch.Stop();
148             //    Console.WriteLine(stopwatch.ElapsedMilliseconds);
149             //});
150             #endregion
151 
152             #region   第四部分  parallel  控制并发量,  比上边的第二部分更简洁
153 
154             /*   
155                 要求:最多3个线程,  并发执行10个任务
156              
157              */
158             //ParallelOptions parallelOptions = new ParallelOptions();//这个可以控制并发数量(即线程数量)
159             //parallelOptions.MaxDegreeOfParallelism = 3;//最多3个线程的要求    在这里可以实现
160             //Parallel.For(0,10,parallelOptions,i=>Console.WriteLine("高薪就业"));
161 
162             /*
163              上边的要卡线程,卡屏,那么要不卡咋办呢?? 包一层呗
164              */
165             //Task.Run(()=> {
166             //    ParallelOptions parallelOptions = new ParallelOptions();//这个可以控制并发数量(即线程数量)
167             //    parallelOptions.MaxDegreeOfParallelism = 3;//最多3个线程的要求    在这里可以实现
168             //    Parallel.For(0, 10, parallelOptions, i => Console.WriteLine("高薪就业"));
169             //});
170             #endregion
171 
172             #region   第五部分  临时变量
173             //for (int i = 0; i < 5; i++)
174             //{
175             //    Task.Run(()=>{
176             //        Thread.Sleep(1000);
177             //        Console.WriteLine(i);
178             //    });
179             //}
180             /*
181              分析上边的输出情况:   应该是每隔1秒钟,输出一个数字分别是  0,1,2,3,4
182             但是实际执行结果确实55555......理想丰满,显示骨感,,,怎么回事>>>????
183 
184             首先分析为什么打印出来全是5????
185                     因为计算机的执行速度是很快的,,,我再sleep(1000)后,i早就变成5了   所以会打印出5,
186                             假如没有sleep也会是5怎么解释?还是太快了,开线程的同时,早就i变为5了
187                                     因为全程只有1个i;
188             想要打印出01234的效果要做如下操作:  这样会有5个k,那么就可以打印出5个不同的数字了
189              */
190             //for (int i = 0; i < 5; i++)
191             //{
192             //    int k = i;
193             //    Task.Run(() => {
194             //        Thread.Sleep(1000);
195             //        Console.WriteLine(k);
196             //    });
197             //}
198             #endregion
199 
200 
201             #region  第六部分 线程安全  lock  重点
202             /*概念刨析:
203                     共有变量:  都能访问局部变量/全局变量/数据库得一个值/硬盘文件
204              线程内部不共享是  安全的  ;  共享就会有问题
205 
206                 上边说明了个什么问题??
207             线程安全的问题:
208                 1.如果所有线程都能访问到,那么这个变量或者实例就是线程不安全的,会发生丢包
209                 2.如果  变量是在线程内部,  那么就是线程安全的   不会发生丢包
210             也有坏处:============
211                 虽然解决了丢包的问题  ,  但是就不能并发了  因为每次只能一个线程去执行  .  牺牲了性能   要尽量缩小lock的范围
212              */
213             //例子:  
214 
215 
216             List<Task> taskList = new List<Task>();
217             List<int> intList = new List<int>();
218             int totalCount = 0;
219             //for (int i = 0; i < 10000; i++)
220             //{
221             //    int newI = i;
222             //    taskList.Add(Task.Run(()=> {
223             //        totalCount += 1;
224             //        intList.Add(newI);
225 
226             //    }));
227             //}
228             Console.WriteLine("=======加锁前后=======");
229 
230             for (int i = 0; i < 10000; i++)
231             {
232                 int newI = i;
233                 taskList.Add(Task.Run(() =>
234                 {
235                     /*  
236                         lock后的方法快,任意时刻只能有一个线程进入
237                         锁只能锁引用类型,  占用这个引用类型的 引用连接    但是不要用string  因为享元
238                      */
239                     lock (myLock)//   加锁后,会输出完整的数
240                     {
241                         totalCount += 1;
242                         intList.Add(newI);
243                     }
244 
245 
246                 }));
247 
248             }
249 
250             Console.WriteLine(totalCount);//输出9995
251             Console.WriteLine(intList.Count);//输出9996   说明这2个都会丢包
252             #endregion
253             Console.ReadKey();
254         }
255     }
256 }

 

标签:一次,Console,WriteLine,Thread,tasks,Task,线程,测试,多线程
来源: https://www.cnblogs.com/messi-10/p/16370067.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有