三沣开发知识 购物 网址 游戏 小说 歌词 地图 快照 股票 美女 新闻 笑话 | 汉字 软件 日历 阅读 下载 图书馆 开发 租车 短信 China
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
vbs/VBScript DOS/BAT hta htc python perl 游戏相关 VBA 远程脚本 ColdFusion ruby专题
autoit seraphzone PowerShell linux shell Lua Golang Erlang 其它教程 CSS/HTML/Xhtml
html5 CSS XML/XSLT Dreamweaver教程 经验交流 开发者乐园 Android开发资料
站长资讯 .NET新手 ASP.NET C# WinForm Silverlight WCF CLR WPF XNA VisualStudio ASP.NET-MVC .NET控件开发 EntityFramework WinRT-Metro Java C++ PHP Delphi Python Ruby C语言 Erlang Go Swift Scala R语言 Verilog 其它语言 架构设计 面向对象 设计模式 领域驱动 Html-Css JavaScript jQuery HTML5 SharePoint GIS技术 SAP OracleERP DynamicsCRM K2 BPM 信息安全 企业信息 Android开发 iOS开发 WindowsPhone WindowsMobile 其他手机 敏捷开发 项目管理 软件工程 SQLServer Oracle MySQL NoSQL 其它数据库 Windows7 WindowsServer Linux
  IT知识库 -> .NET新手区 -> 使用Task的一些知识优化了一下同事的多线程协作取消的一串代码 -> 正文阅读
 

[.NET新手区]使用Task的一些知识优化了一下同事的多线程协作取消的一串代码

使用Task的一些知识优化了一下同事的多线程协作取消的一串代码   最近在看一个同事的代码,代码的本意是在main方法中开启10个线程,用这10个线程来处理一批业务逻辑,在某一时刻当你命令console退出的时候,这个
时候不是立即让console退出,而是需要等待10个线程把检测状态之后的业务逻辑执行完之后再退出,这样做是有道理的,如果强行退出会有可能造成子线程的业
务数据损坏,没毛病吧,业务逻辑大概就是这样。
一:现实场景
由于真实场景的代码比较复杂和繁琐,为了方便演示,我将同事所写的代码抽象一下,类似下面这样,看好了咯~~~

 1 class Program
 2     {
 3         private static int workThreadNums = 0;
 4 
 5         private static bool isStop = false;
 6 
 7         static void Main(string[] args)
 8         {
 9             var tasks = new Task[10];
10 
11 
12             for (int i = 0; i < 10; i++)
13             {
14                 tasks[i] = Task.Factory.StartNew((obj) =>
15                 {
16                     Run();
17                 }, i);
18             }
19 
20             //是否退出
21             string input = Console.ReadLine();
22 
23             while ("Y".Equals(input, StringComparison.OrdinalIgnoreCase))
24             {
25                 break;
26             }
27 
28             isStop = true;
29 
30             while (workThreadNums != 0)
31             {
32                 Console.WriteLine("正在等待线程结束,当前还在运行线程有:{0}", workThreadNums);
33 
34                 Thread.Sleep(10);
35             }
36             Console.WriteLine("准备退出了。。。");
37             Console.Read();
38             Environment.Exit(0);
39         }
40 
41         static void Run()
42         {
43             try
44             {
45                 workThreadNums++;
46 
47                 while (true)
48                 {
49                     if (isStop) break;
50 
51                     Thread.Sleep(1000);
52 
53                     //执行业务逻辑
54                     Console.WriteLine("我是线程:{0},正在执行业务逻辑", Thread.CurrentThread.ManagedThreadId);
55                 }
56             }
57             finally
58             {
59                 workThreadNums--;
60             }
61         }
62     }

      其实扫一下上面的代码应该就知道是用来干嘛的,业务逻辑没毛病,基本可以实现刚才的业务场景,在console退出的时候可以完全确保10个线程都把自己的业
务逻辑处理完毕了。不过从美观角度上来看,这种代码就太low了。。。一点档次都没有,比如存在下面两点问题:
第一点:局部变量太多,又是isStop又是workThreaNums,导致业务逻辑Run方法中掺杂了很多的非业务逻辑,可读性和维护性都比较low。
第二点:main函数在退出的时候用while检测workThreadNums是否为“0”,貌似没问题,但仔细想想这段代码有必要吗?
接下来我把代码跑一下,可以看到这个while检测到了在退出时的workThredNums的中间状态“7”,有点意思吧~~~

二:代码优化
  那上面这段代码怎么优化呢?如何踢掉业务逻辑方法中的非业务代码呢?当然应该从业务逻辑上考虑一下了,其实这个问题的核心就是两点:
1. 如何实现多线程中的协作取消?
2. 如何实现多线程整体执行完毕通知主线程?
这种场景优化千万不要受到前人写的代码所影响,最好忘掉就更好了,不然你会下意识的受到什么workthreadnums,isstop这些变量的左右,不说废话了,如
果你对task并发模型很熟悉的话,你的优化方案很快就会出来的。。。
1. 协作取消:
    直接用一个bool变量来判断子线程是否退出的办法其实是很没有档次的,在net 4.0中有一个类(CancellationTokenSource)专门来解决使用bool变量来判
断的这种很low的场景,而且比bool变量具有更强大的功能,这个会在以后的文章中跟大家去讲。
2. 多线程整体执行完毕通知主线程
    目前我们看到的方式是主线程通过轮询workthreadnums这种没有档次的方式去做的,其实这种方式本质上就是任务串行,而如果你明白task的话,你就知道
有很多的手段是执行任务串行的,比如什么ContinueWith,WhenAll,WhenAny等等方式,所以你只需要将一组task串联到WhenAll之后就可以了。好了,上
面就是我的解决思路,接下来看一下代码吧:

 1  class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             CancellationTokenSource source = new CancellationTokenSource();
 6 
 7             var tasks = new Task[10];
 8 
 9             for (int i = 0; i < 10; i++)
10             {
11                 tasks[i] = Task.Factory.StartNew((m) =>
12                 {
13                     Run(source.Token);
14                 }, i);
15             }
16 
17             Task.WhenAll(tasks).ContinueWith((t) =>
18             {
19                 Console.WriteLine("准备退出了。。。");
20                 Console.Read();
21                 Environment.Exit(0);
22             });
23 
24             string input = Console.ReadLine();
25             while ("Y".Equals(input, StringComparison.OrdinalIgnoreCase))
26             {
27                 source.Cancel();
28             }
29 
30             Console.Read();
31         }
32 
33         static void Run(CancellationToken token)
34         {
35             while (true)
36             {
37                 if (token.IsCancellationRequested) break;
38 
39                 Thread.Sleep(1000);
40 
41                 //执行业务逻辑
42                 Console.WriteLine("我是线程:{0},正在执行业务逻辑", Thread.CurrentThread.ManagedThreadId);
43             }
44         }
45     }

       单从代码量上面看就缩减了17行代码,而且业务逻辑也非常的简单明了,然后再看业务逻辑方法Run,其实你根本就不需要所谓的workThreadNums++,--
的操作,而且多线程下不用锁的话,还容易出现竞态的问题,解决方案就是使用WhenAll等待一组Tasks完成任务,之后再串行要退出的Task任务,是不是很完美,
而协作取消的话,只需将取消的token传递给业务逻辑方法,当主线程执行source.Cancel()方法取消的时候,子线程就会通过IsCancellationRequested感知到主
线程做了取消操作。
好了,就说这么多吧,还是那句话,”因为我们视野的不开阔,导致缺乏解决问题的手段“,所以古话说得好,磨刀不误砍柴工。。。
  .NET新手区 最新文章
将ZIP文件添加到程序集资源文件然后在运行时
Web服务的调用
.NET创建WebService服务简单的例子
多线程编程学习笔记——任务并行库(三)
序列化和反序列化
Spring学习之路
多线程(6)线程同步
ASPX.Net控件
如何写出高性能SQL语句
来份ASP.NET Core尝尝
上一篇文章      下一篇文章      查看所有文章
加:2017-03-13 14:59:09  更:2017-05-14 06:31:14 
 
技术频道: 站长资讯 .NET新手区 ASP.NET C# WinForm Silverlight WCF CLR WPF XNA Visual Studio ASP.NET MVC .NET控件开发 Entity Framework WinRT/Metro Java C++ PHP Delphi Python Ruby C语言 Erlang Go Swift Scala R语言 Verilog 其它语言 架构设计 面向对象 设计模式 领域驱动设计 Html/Css JavaScript jQuery HTML5 SharePoint GIS技术 SAP Oracle ERP Dynamics CRM K2 BPM 信息安全 企业信息化其他 Android开发 iOS开发 Windows Phone Windows Mobile 其他手机开发 敏捷开发 项目与团队管理 软件工程其他 SQL Server Oracle MySQL NoSQL 其它数据库 Windows 7 Windows Server Linux
脚本语言: vbs/VBScript DOS/BAT hta htc python perl 游戏相关 VBA 远程脚本 ColdFusion ruby专题 autoit seraphzone PowerShell linux shell Lua Golang Erlang 其它教程
网站开发: CSS/HTML/Xhtml html5 CSS XML/XSLT Dreamweaver教程 经验交流 开发者乐园 Android开发资料
360图书馆 软件开发资料 文字转语音 购物精选 软件下载 美食菜谱 新闻资讯 电影视频 小游戏 Chinese Culture 股票 租车
生肖星座 三丰软件 视频 开发 短信 中国文化 网文精选 搜图网 美图 阅读网 多播 租车 短信 看图 日历 万年历 2017年12日历
2017-12-17 18:01:38
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT知识库