c#并行任务多种优化方案分享(异步委托)
遇到一个多线程任务优化的问题,现在解决了,分享如下。
假设有四个任务:
任务1:登陆验证(CheckUser)
任务2:验证成功后从Web服务获取数据(GetDataFromWeb)
任务3:验证成功后从数据库获取数据(GetDatFromDb)
任务4:使用2、3的数据执行一个方法 (StartProcess)
一个比较笨的方法(本人最开始的方法,记为方法1)是直接开启一个线程,按照顺序依次执行四个任务:
{
CheckUser();
GetDatFromDb();//从数据库获取数据
GetDataFromWeb();//web服务获取数据
StartProcess();//执行4
}).Start();
但是仔细分析需求我们会发现,任务2和任务3并没有先后区别,事实上两者并无关联,只不过任务4的执行需要任务2和3都已完成作为条件,所以我们可以再开两个线程用于执行任务2和任务3,当两者都执行完毕之后,执行任务4。
在这里使用了两个全局变量用于表示任务2和任务3的状态。用三个线程分别执行任务2、3、4,其中任务4一直在循环监听全局变量的状态,确保在2、3都执行完毕后才执行。
这记为方法2:
private static volatile bool _m3;//任务3的标志位
private static void Main(string[] args)
{
new Thread(delegate
{
CheckUser();
new Thread(delegate
{
GetDatFromDb();//从数据库获取数据
_m2 = true;//标志位置为true
}).Start();
new Thread(delegate
{
GetDataFromWeb();//web服务获取数据
_m3 = true;//标志位置为true
}).Start();
new Thread(delegate
{
while (!(_m3 && _m2))//判断任务2和3是否已执行完毕
{
Thread.Sleep(100);
}
StartProcess();//执行任务4
_m2 = true;
}).Start();
}).Start();
}
以上代码基本上已经可以达到预期目标了,但是由于借助了两个全局变量,尽管在这里不会涉及到同步冲突的问题,但总觉得很不放心,而且当我们需要做扩展的时候,比方说在执行任务4之前,我们还需要加载文件内的数据(GetDataFromFile),那我们必须再添加一个全局标志位,显得有点麻烦。
事实上,Thread类本身已经拥有对这种情况的完美解决方案——join。
在继续执行标准的 COM 和 SendMessage 消息泵处理期间,阻塞调用线程,直到某个线程终止为止。
简单来说,join就是个阻塞方法,在线程1内创建线程2,调用线程2的Join方法,那么线程1将会被阻塞,直到线程2执行完毕。运用到上面的例子就是,在任务4内创建任务2和任务3的线程,调用任务2和任务3的线程的Join方法使任务4阻塞,直到任务2和任务3执行完毕,才继续执行任务4。这记为方法3,代码如下
{
new Thread(delegate
{
CheckUser();
new Thread(delegate
{
Thread task2 = new Thread(delegate
{
GetDatFromDb(); //从数据库获取数据
});
Thread task3 = new Thread(delegate
{
GetDataFromWeb(); //web服务获取数据
});
task2.Start();
task3.Start();
task2.Join();//任务2阻塞
task3.Join();//任务3阻塞
StartProcess(); //执行任务4
}).Start();
}).Start();
}
这样便不需要任何标志位了。这是最理想的解决方案。
另外还有一种解决方案,使用EventWaitHandle
简单来说,就是方法2的进阶版,使用EventWaitHandle控制状态,而不再使用While循环监听,但这里仍旧需要两个全局的EventWaitHandle对象。该方法记为方法4,代码如下
private static EventWaitHandle eventWait2 = new EventWaitHandle(false, EventResetMode.AutoReset);//初始化状态false;
private static void Main(string[] args)
{
new Thread(delegate
{
CheckUser();
new Thread(delegate
{
GetDatFromDb(); //从数据库获取数据
eventWait1.Set(); //标志位置为true
}).Start();
new Thread(delegate
{
GetDataFromWeb(); //web服务获取数据
eventWait2.Set(); //标志位置为true
}).Start();
new Thread(delegate
{
eventWait1.WaitOne();//任务2阻塞,等待
eventWait2.WaitOne();//任务3阻塞,等待
StartProcess(); //执行任务4
}).Start();
}).Start();
}
上述三个优化方案,其实核心思想都是一样的,都是通过开启3个线程分别执行2、3、4任务,其中任务4被阻塞(while循环、eventWait.WaitOne,thread.join),当阻塞解除后,继续执行任务4。也就是说,任务4,其实是一直在等待任务2和任务3的完成。那么,是否有办法让任务2和任务3主动通知任务4呢?即,任务2和任务3完成后,主动执行任务4。
方法当然有:异步委托+回调函数
private static volatile bool _m2;//任务2的标志位
private static volatile bool _m3;//任务3的标志位
private static void Main(string[] args)
{
CheckUser(); //第一步 验证用户
Action step2 = delegate
{
GetDatFromDb(); //从数据库获取数据
_m2 = true; //标志位置为true
};
Action step3 = delegate
{
GetDataFromWeb(); //web服务获取数据
_m3 = true; //标志位置为true
};
step2.BeginInvoke(delegate
{
if (_m2 && _m3) //通过标志位判断2 3是否都已完成
{
lock (obj)//加锁
{
_m2 = false;
if (_m3)//二重验证 防止两者同时进入
StartProcess(); //执行4
}
}
}, null);
step3.BeginInvoke(delegate
{
if (_m2 && _m3) //通过标志位判断2 3是否都已完成
{
lock (obj)
{
_m3 = false;
if (_m2)
StartProcess(); //执行4
}
}
}, null);
}
讲解下代码。首先以委托的方式创建了任务2和任务3的委托对象step2和step3。执行这两个委托的异步调用方法BegInvoke。执行BegInvoke,会创建一个新的线程来执行step2和step3的方法,同时,在执行BeginInvoke的时候还指定了一个回调函数
{
if (_m2 && _m3) //通过标志位判断2 3是否都已完成
{
lock (obj)
{
_m3 = false;
if (_m2)
StartProcess(); //执行4
}
}
}
这个函数会在step2和step3的线程执行完毕后被调用。在这里,我再次使用了标志位来判断step2和step3是否已经运行完成,同时,为了防止一种特殊情:“step2和step3所执行的时间几乎相等,他们会同时通过if(_m2&&_m3)判断,进而执行两次StartProcess” 在这里加了lock锁,并且在lock锁内将标志位重置+二重判断(这里可以参考单例模式的双重锁定原理),确保StarProcess只会执行一次。
如此这般,一个主动通知模式的并行任务便实现了,不过,这种实现方法相较于方法2,实在太过麻烦,尤其在与并发处理方面,个人感觉实用性不太高。
另外,还可以使用观察者模式实现异步委托+回调函数的效果。
c#并行任务多种优化方案分享(异步委托)的更多相关文章
- 老李分享:MySql的insert语句的性能优化方案
老李分享:MySql的insert语句的性能优化方案 性能优化一直是测试人员比较感兴趣的内容,poptest在培训学员的时候也加大了性能测试调优的方面的内容,而性能优化需要经验的积累,经验的积累依 ...
- 优秀后端架构师必会知识:史上最全MySQL大表优化方案总结
本文原作者“ manong”,原创发表于segmentfault,原文链接:segmentfault.com/a/1190000006158186 1.引言 MySQL作为开源技术的代表作之一,是 ...
- AngularJS应用页面切换优化方案
葡萄城的一款尚在研发中的产品,对外名称暂定为X项目.其中使用了已经上市的Wijmo中SpreadJS产品,另外,在研发过程中整理了一些研发总结分享给大家.如本篇的在页面切换的过程中优化方案,欢迎大家跟 ...
- AngularJs应用页面切换优化方案(转)
目录[-] 前言 场景 使用resolve来提前请求数据 为页面加入切换动画 总结 葡萄城的一款尚在研发中的产品,对外名称暂定为X项目.其中使用了已经上市的wijmo中SpreadJS产品,另外,在研 ...
- Adapter优化方案的探索
概要:使用Adapter的注意事项与优化方案本文的例子都可以在结尾处的示例代码连接中看到并下载,如果喜欢请star,如果觉得有纰漏请提交issue,如果你有更好的点子可以提交pull request. ...
- 百度APP移动端网络深度优化实践分享(一):DNS优化篇
本文由百度技术团队“蔡锐”原创发表于“百度App技术”公众号,原题为<百度App网络深度优化系列<一>DNS优化>,感谢原作者的无私分享. 一.前言 网络优化是客户端几大技术方 ...
- [转] 钉钉的H5性能优化方案
对于一个H5的产品,功能无疑很重要,但是性能同样是用户体验中不可或缺的一环.原本H5的渲染性能就不及native的app,如果不把性能优化做起来,将极大地影响用户使用产品的积极性. 用户感受 当用户能 ...
- Lucene底层原理和优化经验分享(1)-Lucene简介和索引原理
Lucene底层原理和优化经验分享(1)-Lucene简介和索引原理 2017年01月04日 08:52:12 阅读数:18366 基于Lucene检索引擎我们开发了自己的全文检索系统,承担起后台PB ...
- 数据库SQL优化大总结之 百万级数据库优化方案(转载)
网上关于SQL优化的教程很多,但是比较杂乱.近日有空整理了一下,写出来跟大家分享一下,其中有错误和不足的地方,还请大家纠正补充. 这篇文章我花费了大量的时间查找资料.修改.排版,希望大家阅读之后,感觉 ...
随机推荐
- Spring4 MVC 多文件上传(图片并展示)
开始需要在pom.xml加入几个jar,分别是 <dependency> <groupId>commons-fileupload</groupId> <art ...
- windows下搭建node.js及npm的工作环境
近期在研究数据可视化D3框架,决定在windows下搭建一个nodejs及npm的工作环境,在网上查了n篇文章,别管是编译源代码安装也好.还是使用node.msi格式安装包也好,总是有问题.终于,功夫 ...
- Thinkphp框架拓展包使用方式详细介绍--验证码实例(十一)
原文:Thinkphp框架拓展包使用方式详细介绍--验证码实例(十一) 拓展压缩包的使用方式详细介绍 1:将拓展包解压:ThinkPHP3.1.2_Extend.zip --> 将其下的 \ ...
- 14.4.3.2 Configuring Multiple Buffer Pool Instances 配置多个buffer pool 实例:
14.4.3.2 Configuring Multiple Buffer Pool Instances 配置多个buffer pool 实例: 对于系统 buffer pool 有多个G的范围, 把b ...
- Linux 技巧之 Grub 超实用技巧
1. 简单介绍 什么是 GRUB?GRUB 全名Grand Unified Boot Loader,它是一个引导装入器 -- 它负责装入内核并引导 Linux 系统.GRUB 还能够引导其他操作系统, ...
- Android输入法扩展之外接键盘中文输入
大家想不想要这样一台Android Surface平板,看着就过瘾吧. watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSVRsZWFrcw==/font/ ...
- thinkphp中URL传参数的几种方式
在thinkphp中,url传参合asp.net中原理类似,下面就单个参数和多个参数传递方式进行一个简单讲解 1.传单个参数 单个参数这种比较简单,例如 想像edit操作里面传递一个id值,如下写法_ ...
- java 获取当期时间之前几小时的时间
Calendar expireDate = Calendar.getInstance(); expireDate.set(Calendar.HOUR_OF_DAY, expireDate.get(Ca ...
- 创建并使用静态库(ar 命令)
创建并使用静态库(ar 命令) archive命令的功能是:创建或改动归档文件或者从归档文件里析取信息.能够简单的理解为一个打包工具,将成员文件依照一定的规则构建到.a文件里, ...
- Struts2第一个工程helloStruts极其基本配置
前面已经准备好了Struts-2.3.15,现在就可以直接搭建Struts2的工程了.前面http://blog.csdn.net/huangchnegdada/article/details/917 ...