使用 .NET4 中的Task优化线程池【.NET4 多核并行】
来源:互联网 发布:山东seo 编辑:程序博客网 时间:2024/06/07 06:34
Task: http://msdn.microsoft.com/en-us/library/system.threading.tasks.task%28VS.100%29.aspx
Task Schedulers: http://msdn.microsoft.com/en-us/library/dd997402.aspx
首先回顾相关场景:最近工作需要一直在.NET4下编写window service。在WindowsService下使用了多线程相关技术。期间就用了到了线程池。使用线程池的目的:在系统中进行多线程并发也担心并发数量太大影响性能。于是使用线程池进行排队。一批一批执行多线程。当我在使用传统的.NET线程池的过程中碰见了一些问题,请看以下代码:
1 try 2 { 3 ThreadPool.SetMaxThreads( 2 , 2 ); 4 5 for ( int i = 0 ; i < 5 ; i ++ ) 6 { 7 ThreadPool.QueueUserWorkItem( new WaitCallback(InvokeThread1), i); 8 } 9 10 } 11 catch 12 { 13 Console.WriteLine( " error " ); 14 }
这里建立一个同时2个线程并发的线程池。在上述代码第7行传入InvokeThread1方法:
static void InvokeThread1( object obj){ throw new NullReferenceException();}
假设程序发生异常,这个异常却让整个程线程池序崩溃了。主程序并未catch到这个exception。也许您会说这本来就是这样的嘛,有什么好贴出来的。但是在.NET4中我们可以避免掉这个问题。(此时体现出.NET4的异常强大)。还有个问题有必要提到:如果一次有两个线程同时并发(一共要执行5个线程,每次并发2个)。假设其中一个线程执行过程中出现了异常,要让这两个线程以外的三个线程都停止运行,来节省系统资源。传统的线程池也许可以做到,但是控制起来估计不会让你太轻松。但是在.NET4的Task机制中,这些都得到了妥善的解决,现将以上两个问题解决方案给出。如果存在不足的地方,请您指出。
一、自定义TaskScheduler
TaskScheduler 代码如下:
1 // 自定义TaskScheduler 2 public class CustomTaskScheduler : TaskScheduler, IDisposable 3 { 4 // 调用Task的线程 5 Thread[] _Threads; 6 7 // Task Collection 8 BlockingCollection < Task > _Tasks = new BlockingCollection < Task > (); 9 10 int _ConcurrencyLevel; 11 12 13 // 设置schedule并发 14 public CustomTaskScheduler( int concurrencyLevel) 15 { 16 17 _Threads = new Thread[concurrencyLevel]; 18 this ._ConcurrencyLevel = concurrencyLevel; 19 20 21 for ( int i = 0 ; i < concurrencyLevel; i ++ ) 22 { 23 _Threads[i] = new Thread(() => 24 { 25 foreach (Task task in _Tasks.GetConsumingEnumerable()) 26 this .TryExecuteTask(task); 27 28 }); 29 30 _Threads[i].Start(); 31 } 32 33 } 34 35 protected override void QueueTask(Task task) 36 { 37 _Tasks.Add(task); 38 } 39 40 41 protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) 42 { 43 44 if (_Threads.Contains(Thread.CurrentThread)) return TryExecuteTask(task); 45 46 return false ; 47 } 48 49 public override int MaximumConcurrencyLevel 50 { 51 get 52 { 53 return _ConcurrencyLevel; 54 } 55 } 56 57 58 protected override IEnumerable < Task > GetScheduledTasks() 59 { 60 return _Tasks.ToArray(); 61 } 62 63 64 public void Dispose() 65 { 66 this ._Tasks.CompleteAdding(); 67 foreach (Thread t in _Threads) 68 { 69 t.Join(); 70 } 71 72 } 73 }
该scheduler代码很简单,重写相关System.Threading.Tasks.TaskScheduler类下的相关方法即可,代码中已给出相关注释。
二、使用自定义的TaskScheduler
调用TaskScheduler代码:
1 List < string > listMsg = new List < string > () { " Task1 " , " Task2 " , " Task3 " , " Task4 " , " Task5 " , " Task6 " }; 2 List < Task > listTask = new List < Task > (); 3 4 foreach ( string msg in listMsg) 5 { 6 Task myTask = new Task(obj => InvokeThread2(( string )obj), msg, token); 7 listTask.Add(myTask); 8 myTask.Start(customTaskScheduler); 9 } 10 11 try 12 { 13 // 等待所有线程全部运行结束 14 Task.WaitAll(listTask.ToArray()); 15 } 16 catch (AggregateException ex) 17 { 18 // .NET4 Task的统一异常处理机制 19 foreach (Exception inner in ex.InnerExceptions) 20 { 21 Console.WriteLine( " Exception type {0} from {1} " , 22 inner.GetType(), inner.Source); 23 } 24 } 25 26 Console.ReadLine();
InvokeThread2 相关代码:
static void InvokeThread2( string msg){ try {var x = Convert.ToInt32(msg.Replace( " Task " , "" ).Trim());Console.WriteLine(msg);Thread.Sleep( 1000 * 5 );Console.WriteLine( " {0} ok " , msg);} catch (Exception ex){ // 如果有异常发生则取消正在排队的所有线程。 tokenSource.Cancel();Exception exception = new Exception( " error " );exception.Source = msg; throw exception;}}
以上代码运行效果如下:
接着在TaskScheduler调用代码中如果将第一行代码listMsg值修改成 List<string> listMsg = new List<string>() { "Task1", "Task2", "TaskA", "Task3", "Task4", "Task5", "Task6", "Task7", "Task8", "Task9" };这时候我们将得到以下结果:
这个运行结果重点要强调的地方为:后面这7个exception。聪明的您或许已经看出来前6个exception属于没有执行的"Task4", "Task5", "Task6", "Task7", "Task8", "Task9",而最后一个exception才是真正的发生异常的"TaskA"。这里主要用到了Task的统一异常处理机制AggregateException 。可以从运行结果得到:Task1,Task2,Task3执行成功了,但是TaskA发生了异常导致了后面排队的"Task4", "Task5", "Task6", "Task7", "Task8", "Task9"都不会执行了。节省了系统资源,同时也提高了系统性能。
三、小结
本文主要用到了的是.NET4 的Task相关技术,Task让我们在多核并行控制的时候更加简单,功能更加强大。如果需进一步了解相关技术,博客园已经有不少教程。微软的MSDN也提供了很多参考资料。 最后希望本文可以给您的开发带来帮助。
- 使用 .NET4 中的Task优化线程池【.NET4 多核并行】
- 使用 .NET4 中的Task优化线程池【.NET4 多核并行】
- (译).NET4.X并行任务Task需要释放吗?
- .Net4.0 任务(Task)
- .Net4.0 任务(Task)
- .Net4.0 任务(Task)
- .Net4.0 任务(Task)
- .Net4.0 任务(Task)
- .Net4.0 任务(Task)
- .Net4.0 任务(Task)
- .Net4.0 任务(Task)
- 使用.net4.0中的并行计算来处PI值,及多线程处理比较
- .net4.0实现.net4.5 Task.Run的方法
- .Net4.0 Dynamic 使用
- c#中的高级语法(.Net4)
- .NET4中Task类和Parallel类的一些简单使用
- .Net4 常见问题
- .NET4.0并行计算技术基础(1)
- 动态连接库(dll)生成及应用程序载入dll过程分析
- COM编程的技术基础分享
- 基于V4L2的视频驱动开发
- maven2之m2eclipse使用手册之六使用Maven2插件创建一个简单的SSH2项目之jetty篇(一)
- ie6,ie8,firefox中padding的兼容性
- 使用 .NET4 中的Task优化线程池【.NET4 多核并行】
- Linux常用网络操作
- 利用PL/SQL Developer工具导入excel数据
- 计划任务安排
- Linux创建、修改、删除用户
- activemq安全设置 设置admin的用户名和密码
- Linux目录结构
- tar命令详解
- java.lang.OutOfMemoryError: PermGen space及其解决方法