C# 并行开发总结

时间:2023-06-14 19:46:38

本文内容 均参考自 《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();
}
} }
}