C# 并行开发总结
本文内容 均参考自 《C#并行高级编程》
TPL 支持 数据并行(有大量数据要处理,必须对每个数据执行同样的操作, 任务并行(有好多可以并发运行的操作),流水线(任务并行和数据并行的结合体)
在.net 4.0 引入新的 Task Parallel Library 处理 并行开发 。
Parallel类
关键词 :
Parallel.For and Parallel.Foreach - 负载均衡的多任务
Parallel.Invoke - 并行运行多任务
ParallelOptions - 指定最大并行度 (实例化一个类并修改MaxDegreeOfParallelism 属性的值 )
Environment.ProcessorCount - 内核最大数
命令式任务并行
关键词 : Task类 , 一个task 类表示一个异步操作 (需要考虑到任务的开销)
启动任务使用Task类的Start 方法 , 等待线程完成使用WaitAll 方法 , 通过CancellationTokenSource 的Cancel方法来 中断 Task的运行
怎样表达任务间的父子关系 ? TaskCreationOption的AttachToParent来完成
怎样来表达串行任务 ? Task.ContinueWith
并发集合
BlockingCollection
ConcurrentDictionary/ConcurrentQueue/ConcurrentStack
下面来一个例子是实操 C# 多任务并发。
场景 : 主进程 打开 一个 生产者线程 和 一个消费线程 。 他们之间可以相互对话, 如([动词,名词]) say,hello task,a . 生产者说一句话 消费者听, 消费者或应答或提交新的任务或结束自己。
代码
using System; using System.Threading; using System.Threading.Tasks; using System.Collections.Concurrent; namespace TPLTest { class Program { public static readonly int MAX_DATA_LENGTH = 256; private static BlockingCollection<Message> bcstr = new BlockingCollection<Message>(MAX_DATA_LENGTH) ; public static readonly string SAY_THANKS = "thanks"; public static readonly string SAY_WELCOME = "welcome!"; public static readonly string BYE = "bye"; public static readonly string SAY = "say"; public static readonly string TASK = "task"; public static readonly string TIMEOUT = "timeout"; public static readonly string ONLINE = "ONLINE"; public static readonly string WHAT = "What?"; public static readonly int WAIT = 20000; public static void Main(string[] args) { //消费者线程 ParallelOptions po = new ParallelOptions(); po.MaxDegreeOfParallelism = -1; Parallel.Invoke(po,() => { int selfID = Environment.CurrentManagedThreadId; Message customer = new Message(); customer.CustomerThreadID = selfID ; customer.content = ONLINE; Console.WriteLine(customer.ToString(false)); while(true){ if (bcstr.TryTake(out customer, WAIT)) { customer.CustomerThreadID = selfID ; customer.doAction(); Console.WriteLine(" "); Console.WriteLine(customer.ToString(false)); if (customer.endThread()){ break; } } else { if (customer == null) { customer = new Message(); } customer.CustomerThreadID = selfID ; customer.content = TIMEOUT; Console.WriteLine(customer.ToString(false)); } } }, () => { int prdID = Environment.CurrentManagedThreadId; Message productor = new Message(); productor.ProductorThreadID = prdID; productor.content = ONLINE; Console.WriteLine(productor.ToString(true)); while(true){ Console.Write("Productor Behavior (i.e. say,hello) : "); string msgContent = Console.ReadLine(); productor = new Message(); productor.ProductorThreadID = prdID; productor.key = msgContent.Split(',')[0]; productor.content = msgContent.Split(',')[1]; bcstr.Add(productor); if (productor.endThread()) { break; } } }); } } class Message { public int ProductorThreadID {get; set;} public int CustomerThreadID {get; set;} public string key {get; set;} public string content{get; set;} public bool endThread() { return string.Compare(key, Program.BYE) == 0; } public string ToString(bool isProductor){ return string.Format("{0} Thread ID {1} : {2}", isProductor ? "Productor" : "Customer", isProductor ? ProductorThreadID.ToString() : CustomerThreadID.ToString(), content); } public void doAction(){ if (string.Compare(key, Program.SAY) == 0) { content = string.Compare(content, Program.SAY_THANKS) == 0 ? Program.SAY_WELCOME : Program.WHAT; } if (string.Compare(key, Program.TASK) == 0) { Task taskA = Task.Factory.StartNew(() => { Console.WriteLine("task A begin "); Task ChildOfFatehrA = Task.Factory.StartNew(() => { Console.WriteLine("Sub task A begin "); Thread.Sleep(1000); Console.WriteLine("Sub task A end "); }); ChildOfFatehrA.Wait(); Console.WriteLine("task A end "); }); taskA.ContinueWith(taskB => { Console.WriteLine("task B begin "); Thread.Sleep(5000); Console.WriteLine("task B end "); }); taskA.Wait(); } } } }