5天玩转C#并行和多线程编程 —— 第五天 多线程编程大总结
5天玩转C#并行和多线程编程系列文章目录
5天玩转C#并行和多线程编程 —— 第一天 认识Parallel
5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq
5天玩转C#并行和多线程编程 —— 第三天 认识和使用Task
5天玩转C#并行和多线程编程 —— 第五天 多线程编程大总结
1、死锁问题
前面我们学习了Task的使用方法,其中Task的等待机制让我们瞬间爱上了它,但是如果我们在调用Task.WaitAll方法等待所有线程时,如果有一个Task一直不返回,会出现什么情况呢?当然,如果我们不做出来的话,程序会一直等待下去,那么因为这一个Task的死锁,导致其他的任务也无法正常提交,整个程序"死"在那里。下面我们来写一段代码,来看一下死锁的情况:
var t1 = Task.Factory.StartNew(() =>
{
Console.WriteLine("Task 1 Start running...");
while(true)
{
System.Threading.Thread.Sleep();
}
Console.WriteLine("Task 1 Finished!");
});
var t2 = Task.Factory.StartNew(() =>
{
Console.WriteLine("Task 2 Start running...");
System.Threading.Thread.Sleep();
Console.WriteLine("Task 2 Finished!");
});
Task.WaitAll(t1,t2);
这里我们创建两个Task,t1和t2,t1里面有个while循环,由于条件一直为TRUE,所以他永远也无法退出。运行程序,结果如下:
可以看到Task2完成了,就是迟迟等不到Task1,这个时候我们按回车是没有反应的,除非关掉窗口。如果我们在项目中遇到这种情况是令人很纠结的,因为我们也不知道到底发生了什么,程序就是停在那里,也不报错,也不继续执行。
那么出现这种情况我们该怎么处理呢?我们可以设置最大等待时间,如果超过了等待时间,就不再等待,下面我们来修改代码,设置最大等待时间为5秒(项目中可以根据实际情况设置),如果超过5秒就输出哪个任务出错了,代码如下:
Task[] tasks = new Task[];
tasks[] = Task.Factory.StartNew(() =>
{
Console.WriteLine("Task 1 Start running...");
while(true)
{
System.Threading.Thread.Sleep();
}
Console.WriteLine("Task 1 Finished!");
});
tasks[] = Task.Factory.StartNew(() =>
{
Console.WriteLine("Task 2 Start running...");
System.Threading.Thread.Sleep();
Console.WriteLine("Task 2 Finished!");
}); Task.WaitAll(tasks,);
for (int i = ; i < tasks.Length;i++ )
{
if (tasks[i].Status != TaskStatus.RanToCompletion)
{
Console.WriteLine("Task {0} Error!",i + );
}
}
Console.Read();
这里我们将所有任务放到一个数组里面进行管理,调用Task.WaitAll的一个重载方法,第一个参数是Task[]数据,第二个参数是最大等待时间,单位是毫秒,这里我们设置为5000及等待5秒钟,就继续向下执行。下面我们遍历Task数组,通过Status属性判断哪些Task没有完成,然后输出错误信息。
2、SpinLock(自旋锁)
我们初识多线程或者多任务时,第一个想到的同步方法就是使用lock或者Monitor,然而在4.0 之后微软给我们提供了另一把利器——spinLock,它比重量级别的Monitor具有更小的性能开销,它的用法跟Monitor很相似,VS给的提示如下:
下面我们来写一个例子看一下,代码如下(关于lock和Monitor的用法就不再细说了,网上资料很多,大家可以看看):
SpinLock slock = new SpinLock(false);
long sum1 = ;
long sum2 = ;
Parallel.For(, , i =>
{
sum1 += i;
}); Parallel.For(, , i =>
{
bool lockTaken = false;
try
{
slock.Enter(ref lockTaken);
sum2 += i;
}
finally
{
if (lockTaken)
slock.Exit(false);
}
}); Console.WriteLine("Num1的值为:{0}", sum1);
Console.WriteLine("Num2的值为:{0}", sum2); Console.Read();
输出结果如图:
这里我们使用了Parallel.For方法来做演示,Parallel.For用起来方便,但是在实际开发中还是尽量少用,因为它的不可控性太高,有点简单粗暴的感觉,可能带来一些不必要的"麻烦",最好还是使用Task,因为Task的可控性较好。
slock.Enter方法,解释如下:
3、多线程之间的数据同步
多线程间的同步,在用thread的时候,我们常用的有lock和Monitor,上面刚刚介绍了.Net4.0中一个新的锁——SpinLock(自旋锁),实际上,我们还可以将任务分成多块,由多个线程一起执行,最后合并多个线程的结果,如:求1到100的和,我们分10个线程,分别求1~10,......,90~100的和,然后合并十个线程的结果。还有就是使用线程安全集合,可参加第二天的文章。其实Task的同步机制做已经很好了,如果有特殊业务需求,有线程同步问题,大家可一起交流~~
我们要说的task的知识也说的差不多了,接下来我们开始站在理论上了解下“线程池”和“任务”之间的关系,我们要做到知其然,还要知其所以然。不管是说线程还是任务,我们都不可避免的要讨论下线程池,然而在.net 4.0以后,线程池引擎考虑了未来的扩展性,已经充分利用多核微处理器架构,只要在可能的情况下,我们应该尽量使用task,而不是线程池。
这里简要的分析下CLR线程池,其实线程池中有一个叫做“全局队列”的概念,每一次我们使用QueueUserWorkItem的使用都会产生一个“工作项”,然后“工作项”进入“全局队列”进行排队,最后线程池中的的工作线程以FIFO(First Input First Output)的形式取出,这里值得一提的是在.net 4.0之后“全局队列”采用了无锁算法,相比以前版本锁定“全局队列”带来的性能瓶颈有了很大的改观。那么任务委托的线程池不光有“全局队列”,而且每一个工作线程都有”局部队列“。我们的第一反应肯定就是“局部队列“有什么好处呢?这里暂且不说,我们先来看一下线程池中的任务分配,如下图:
线程池的工作方式大致如下,线程池的最小线程数是6,线程1~3正在执行任务1~3,当有新的任务时,就会向线程池请求新的线程,线程池会将空闲线程分配出去,当线程不足时,线程池就会创建新的线程来执行任务,直到线程池达到最大线程数(线程池满)。总的来说,只有有任务就会分配一个线程去执行,当FIFO十分频繁时,会造成很大的线程管理开销。
下面我们来看一下task中是怎么做的,当我们new一个task的时候“工作项”就会进去”全局队列”,如果我们的task执行的非常快,那么“全局队列“就会FIFO的非常频繁,那么有什么办法缓解呢?当我们的task在嵌套的场景下,“局部队列”就要产生效果了,比如我们一个task里面有3个task,那么这3个task就会存在于“局部队列”中,如下图的任务一,里面有三个任务要执行,也就是产生了所谓的"局部队列",当任务三的线程执行完成时,就会从任务一种的队列中以FIFO的形式"窃取"任务执行,从而减少了线程管理的开销。这就相当于,有两个人,一个人干完了分配给自己的所有活,而另一个人却还有很多的活,闲的人应该接手点忙的人的活,一起快速完成。
从上面种种情况我们看到,这些分流和负载都是普通ThreadPool.QueueUserWorkItem所不能办到的,所以说在.net 4.0之后,我们尽可能的使用TPL,抛弃ThreadPool。
这是5天玩转C#并行和多线程编程系列的最后一篇了,当然还有很多东西没说到,如果真的想要玩转多线程,还是要多多努力学习的。大家在学习过程中有什么问题可以一起交流~~
如果大家感觉我的博文对大家有帮助,请推荐支持一把,给我写作的动力。
作者:雲霏霏
博客地址:http://www.cnblogs.com/yunfeifei/
声明:本博客原创文字只代表本人工作中在某一时间内总结的观点或结论,与本人所在单位没有直接利益关系。非商业,未授权,贴子请以现状保留,转载时必须保留此段声明,且在文章页面明显位置给出原文连接。
5天玩转C#并行和多线程编程 —— 第五天 多线程编程大总结的更多相关文章
- 5天玩转C#并行和多线程编程 —— 第四天 Task进阶
5天玩转C#并行和多线程编程系列文章目录 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel 5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq 5天玩转C#并行和多线程编 ...
- 5天玩转C#并行和多线程编程 —— 第三天 认识和使用Task
5天玩转C#并行和多线程编程系列文章目录 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel 5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq 5天玩转C#并行和多线程编 ...
- 5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq
5天玩转C#并行和多线程编程系列文章目录 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel 5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq 5天玩转C#并行和多线程编 ...
- 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel
5天玩转C#并行和多线程编程系列文章目录 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel 5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq 5天玩转C#并行和多线程编 ...
- 5天玩转C#并行和多线程编程
5天玩转C#并行和多线程编程系列文章目录 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel 5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq 5天玩转C#并行和多线程编 ...
- 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel 转载 https://www.cnblogs.com/yunfeifei/p/3993401.html
5天玩转C#并行和多线程编程系列文章目录 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel 5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq 5天玩转C#并行和多线程编 ...
- C#编程总结(五)多线程带给我们的一些思考
C#编程总结(五)多线程带给我们的一些思考 如有不妥之处,欢迎批评指正. 1.什么时候使用多线程? 这个问题,对于系统架构师.设计者.程序员,都是首先要面对的一个问题. 在什么时候使用多线程技术? 在 ...
- JavaEE基础(二十五)/多线程、GUI
1.多线程(单例设计模式) 单例设计模式:保证类在内存中只有一个对象. 如何保证类在内存中只有一个对象呢? (1)控制类的创建,不让其他类来创建本类的对象.private (2)在本类中定义一个本类的 ...
- Python之FTP多线程下载文件之分块多线程文件合并
Python之FTP多线程下载文件之分块多线程文件合并 欢迎大家阅读Python之FTP多线程下载系列之二:Python之FTP多线程下载文件之分块多线程文件合并,本系列的第一篇:Python之FTP ...
随机推荐
- winrar命令行加压解密
加密的操作 Rar.exe a -P123 test1.rar test.txt 其中参数a表示添加文件或文件夹到压缩包中,-P参数表示是带密码的加密 Rar.exe e -P123 test1.ra ...
- webform的页面缓存
给页面添加<%@ OutputCache Duration="10" VaryByParam="*"%>标签就可以启用页面缓存. Duration表 ...
- aa4
// 初始化地图 var BMapExt = new BMapExtension(domMain, BMap, require('echarts'), require('zrender')); var ...
- CSS3制作各种形状图像
圆形-椭圆形-三角形-倒三角形=左三角形-右三角形-菱形-平行四边形- 星形-六角星形-五边形-六边形-八角形-心形-蛋形-无穷符号-消息提示框 不废话直接 html界面(亲测的) ------转自百 ...
- ckeditor使用
安装: 下载CKEDITOR的文件,解压后复制到工程的WEBROOT目录下就OK! 引用CKEDITOR的JS文件: 新建JSP页面,添加其JS文件<script type="text ...
- css 3 动画
1.transition,其作用是:平滑的改变CSS的值.无论是点击事件,焦点事件,还是鼠标hover,只要值改变了,就是平滑的,就是动画. transition 属性介绍: transition-p ...
- tab栏切换的特殊效果
在实际的开发过程中,我们可能会遇到这种需求,如下图 左边是三个tab栏,右边是显示内容的div,当鼠标滑到坐标的tab上时,给它一个高亮显示,让它对应的内容在右边的div中显示出来,当鼠标移出的时候把 ...
- 分组背包——sicily 1750
1750. 运动会 限制条件 时间限制: 1 秒, 内存限制: 32 兆 题目描述 ZEH是一名04级的学生,他除了绩点高,还有运动细胞.有一次学院举办运动会,ZEH发现里面的 项目都是他所向披靡的, ...
- zTree+EasyUi做权限遇到的小问题
最近需要做一个zTree+EasyUi的权限管理系统,以前有过接触,在做这一块时,用到了ztree,树来加载咱们的菜单栏,后台获取登录用户信息的权限列表,转换成json对象来加载到咱们的树当中,代码如 ...
- vs的一些配置
C/C++ -> 常规 -> 附加包含目录 添加头文件位置.例如 $(ProjectDir)..\..\MsUtil\MsTools\include C/C++ -> ...