CountdownEvent
//默认的容纳大小为“硬件线程“数 static CountdownEvent cde = new CountdownEvent(Environment.ProcessorCount); static void Main(string[] args) { //加载User表需要5个任务 var userTaskCount = 5; cde.Reset(userTaskCount); for(int i=0;i<userTaskCount;i++) { Task.Factory.StartNew((obj) => { LoadUser(obj); }, i); } //等待所有任务执行完毕 cde.Wait(); Console.WriteLine("\nUser表数据全部加载完毕!\n"); var productTaskCount = 8; cde.Reset(productTaskCount); for (int i = 0; i < productTaskCount; i++) { Task.Factory.StartNew((obj) => { LoadProduct(obj); }, i); } cde.Wait(); Console.WriteLine("\nProduct表数据全部加载完毕!\n"); var orderTaskCount = 8; cde.Reset(productTaskCount); for (int i = 0; i < orderTaskCount; i++) { Task.Factory.StartNew((obj) => { LoadOrder(obj); }, i); } cde.Wait(); Console.WriteLine("\nOrder表数据全部加载完毕!\n"); Console.WriteLine("\n数据全部加载完毕\n"); Console.ReadKey(); } private static void LoadUser(object obj) { try { Console.WriteLine("当前任务:{0}正在加载User部分数据!", obj); } finally { cde.Signal(); } } private static void LoadProduct(object obj) { try { Console.WriteLine("当前任务:{0}正在加载Product部分数据!", obj); } finally { cde.Signal(); } } private static void LoadOrder(object obj) { try { Console.WriteLine("当前任务:{0}正在加载Order部分数据!", obj); } finally { cde.Signal(); } }我们看到有两个主要方法:Wait和Signal。每调用一次Signal相当于麻将桌上走了一个人,直到所有人都搓过麻将wait才给放行。
SemaphoreSlim
static SemaphoreSlim slim = new SemaphoreSlim(Environment.ProcessorCount, 12); static void Main(string[] args) { for(int i=0;i<12;i++) { Task.Factory.StartNew((obj) => { Run(obj); }, i); } Console.ReadKey(); } private static void Run(object obj) { slim.Wait(); Console.WriteLine("当前时间:{0}任务 {1}已经进入。", DateTime.Now, obj); Thread.Sleep(3000); slim.Release(); }ManualResetEventSlim
这个轻量级别采用的是"自旋等待“+”内核等待“,也就是说先采用”自旋等待的方式“等待,直到另一个任务调用set方法来释放它。如果迟迟等不到释放,那么任务就会进入基于内核的等待,所以说如果我们知道等待的时间比较短,采用轻量级的版本会具有更好的性能,原理大概就这样,下面举个小例子。
static ManualResetEventSlim mrs = new ManualResetEventSlim(false, 2047); static void Main(string[] args) { for(int i=0;i<12;i++) { Task.Factory.StartNew((obj) => { Run(obj); }, i); } Console.WriteLine("当前时间:{0}我是主线程{1},你们这些任务都等2s执行吧:\n", DateTime.Now, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(2000); mrs.Set(); Console.ReadKey(); } private static void Run(object obj) { mrs.Wait(); Console.WriteLine("当前时间:{0}任务 {1}已经进入。", DateTime.Now, obj); }