问答 百科手机端

转载不休 NET 4.0 (5)

2023-04-29 12:49

精进不休 .NET 4.0 (5) - C# 4.0 新特性之并行运算(Parallel)


介绍
C# 4.0 的新特性之并行运算

Parallel.For - for 循环的并行运算
Parallel.ForEach - foreach 循环的并行运算
Parallel.Invoke - 并行调用多个任务
Task - 任务,基于线程池。其使我们对并行编程变得更简单,且不用关心底层是怎么实现的
PLINQ - 用于对内存中的数据做并行运算,也就是说其只支持 LINQ to Object 的并行运算

示例
1、Parallel.For 的 Demo
Parallel/ParallelFor.aspx.cs

代码
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Web;
usingSystem.Web.UI;
usingSystem.Web.UI.WebControls;

namespaceCSharp.Parallel
{
publicpartialclassParallelFor:System.Web.UI.Page
{
protectedvoidPage_Load(objectsender,EventArgse)
{
Normal ;
ParallelForDemo ;
}

privatevoidNormal
{
DateTimedt=DateTime.Now;

for(inti=0;i<20;i++)
{
GetData(i);
}

Response.Write((DateTime.Now-dt).TotalMilliseconds.ToString );
Response.Write('<br/>');
Response.Write('<br/>');
}

privatevoidParallelForDemo
{
DateTimedt=DateTime.Now;

//System.Threading.Tasks.Parallel.For-for循环的并行运算
System.Threading.Tasks.Parallel.For(0,20,(i)=>{GetData(i);});

Response.Write((DateTime.Now-dt).TotalMilliseconds.ToString );
Response.Write('<br/>');
}

privateintGetData(inti)
{
System.Threading.Thread.Sleep(100);
Response.Write(i.ToString );
Response.Write('<br/>');
returni;
}
}
}

/*
运行结果:
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2000.0514

0
13
1
19
7
12
18
6
2
8
10
14
4
16
5
3
15
17
9
11
300.0077
*/

2、Parallel.ForEach 的 Demo
Parallel/ParallelForEach.aspx.cs

代码
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Web;
usingSystem.Web.UI;
usingSystem.Web.UI.WebControls;

namespaceCSharp.Parallel
{
publicpartialclassParallelForEach:System.Web.UI.Page
{
privateList<int>_data=newList<int> ;

protectedvoidPage_Load(objectsender,EventArgse)
{
InitData ;

Normal ;
ParallelForEachDemo ;
}

privatevoidInitData
{
_data.Clear ;
for(inti=0;i<20;i++)
{
_data.Add(i);
}
}

privatevoidNormal
{
DateTimedt=DateTime.Now;

for(inti=0;i<20;i++)
{
GetData(i);
}

Response.Write((DateTime.Now-dt).TotalMilliseconds.ToString );
Response.Write('<br/>');
Response.Write('<br/>');
}

privatevoidParallelForEachDemo
{
DateTimedt=DateTime.Now;

//System.Threading.Tasks.Parallel.ForEach-foreach循环的并行运算
System.Threading.Tasks.Parallel.ForEach(_data,(index)=>{GetData(index);});

Response.Write((DateTime.Now-dt).TotalMilliseconds.ToString );
Response.Write('<br/>');
}

privateintGetData(inti)
{
System.Threading.Thread.Sleep(100);
Response.Write(i.ToString );
Response.Write('<br/>');
returni;
}
}
}

/*
运行结果:
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2000.0514

0
6
12
18
1
2
7
13
19
4
3
8
14
9
5
15
10
16
11
17
600.0154
*/

3、Parallel.Invoke 的 Demo
Parallel/ParallelInvoke.aspx.cs

代码
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Web;
usingSystem.Web.UI;
usingSystem.Web.UI.WebControls;

usingSystem.Threading;

namespaceCSharp.Parallel
{
publicpartialclassParallelInvoke:System.Web.UI.Page
{
protectedvoidPage_Load(objectsender,EventArgse)
{
vartasks=newAction[]{ =>Task1 , =>Task2 , =>Task3 };

//System.Threading.Tasks.Parallel.Invoke-并行调用多个任务
System.Threading.Tasks.Parallel.Invoke(tasks);
}

privatevoidTask1
{
Thread.Sleep(3000);
Response.Write('Task1-'+'ThreadId:'+Thread.CurrentThread.ManagedThreadId.ToString +'-'+DateTime.Now.ToString('HH:mm:ss'));
Response.Write('<br/>');
}

privatevoidTask2
{
System.Threading.Thread.Sleep(3000);
Response.Write('Task2-'+'ThreadId:'+Thread.CurrentThread.ManagedThreadId.ToString +'-'+DateTime.Now.ToString('HH:mm:ss'));
Response.Write('<br/>');
}

privatevoidTask3
{
System.Threading.Thread.Sleep(3000);
Response.Write('Task3-'+'ThreadId:'+Thread.CurrentThread.ManagedThreadId.ToString +'-'+DateTime.Now.ToString('HH:mm:ss'));
Response.Write('<br/>');
}
}
}

/*
运行结果:
Task2-ThreadId:26-09:11:58
Task1-ThreadId:25-09:11:58
Task3-ThreadId:24-09:11:58
*/

4、Task 的 Demo
Parallel/ParallelTask.aspx.cs

代码
/*
Task-任务,基于线程池。其使我们对并行编程变得更简单,且不用关心底层是怎么实现的
*/

usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Web;
usingSystem.Web.UI;
usingSystem.Web.UI.WebControls;

usingSystem.Threading;
usingSystem.Threading.Tasks;

namespaceCSharp.Parallel
{
publicpartialclassParallelTask:System.Web.UI.Page
{
protectedvoidPage_Load(objectsender,EventArgse)
{
/*
*CancellationTokenSource-取消任务的操作需要用到的一个类
*Token-一个CancellationToken类型的对象,用于通知取消指定的操作
*IsCancellationRequested-是否收到了取消操作的请求
*Cancel -结束任务的执行
*ParallelOptions-并行运算选项
*CancellationToken-设置一个Token,用于取消任务时的相关操作
*MaxDegreeOfParallelism-指定一个并行循环最多可以使用多少个线程
*/

CancellationTokenSourcects=newCancellationTokenSource ;
ParallelOptionspOption=newParallelOptions {CancellationToken=cts.Token};
pOption.MaxDegreeOfParallelism=10;

Response.Write('开始执行,3.5秒后结束');
Response.Write('<br/>');

/*
*Task-任务类
*Factory.StartNew -创建并开始一个或一批新任务
*ContinueWith -此任务完成后执行指定的另一个任务
*AsyncState-此任务的上下文对象
*Wait -阻塞,直到任务完成
*/

Tasktask0=Task.Factory.StartNew( =>
{
Thread.Sleep(3500);
cts.Cancel ;
Response.Write('结束');
Response.Write('<br/>');

});

//通过System.Threading.Tasks.Parallel.Invoke执行任务的时候,可以加入ParallelOptions参数,用于对此并行运算做一些配置
System.Threading.Tasks.Parallel.Invoke(pOption,
=>Task1(pOption.CancellationToken),
=>Task2(pOption.CancellationToken));

/*
*一个Task内可以包含多个Task
Tasktasks=newTask( =>
{
Task.Factory.StartNew( =>Method );
Task.Factory.StartNew( =>Method2 );
Task.Factory.StartNew( =>Method3 );
});
tasks.Start ;
//阻塞,直到整个任务完成
tasks.Wait ;
*/

/*
*带返回值的Task
Func<object,long>fun=delegate(objectstate)
{
return1.0;
};
Task<long>tsk=newTask<long>(fun,'state');
tsk.Start ;
Response.Write(tsk.Result.ToString );
*/
}

privatevoidTask1(CancellationTokentoken)
{
//每隔1秒执行一次,直到此任务收到了取消的请求
//注意:虽然此处是其他线程要向主线程(UI线程)上输出信息,但因为使用了Task,所以不用做任何处理
while(!token.IsCancellationRequested)
{
Response.Write('Task1-'+'ThreadId:'+Thread.CurrentThread.ManagedThreadId.ToString );
Response.Write('<br/>');
Thread.Sleep(1000);
}

}
privatevoidTask2(CancellationTokentoken)
{
while(!token.IsCancellationRequested)
{
Response.Write('Task2-'+'ThreadId:'+Thread.CurrentThread.ManagedThreadId.ToString );
Response.Write('<br/>');
Thread.Sleep(1000);
}
}
}
}

/*
运行结果:
开始执行,3.5秒后结束
Task2-ThreadId:6
Task1-ThreadId:48
Task1-ThreadId:48
Task2-ThreadId:6
Task2-ThreadId:6
Task1-ThreadId:48
Task2-ThreadId:6
Task1-ThreadId:48
结束
*/

5、PLINQ 的 Demo
Parallel/ParallelPLINQ.aspx.cs

代码
/*
PLINQ-用于对内存中的数据做并行运算,也就是说其只支持LINQtoObject的并行运算
*/

usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Web;
usingSystem.Web.UI;
usingSystem.Web.UI.WebControls;

namespaceCSharp.Parallel
{
publicpartialclassParallelPLINQ:System.Web.UI.Page
{
protectedvoidPage_Load(objectsender,EventArgse)
{
List<int>list=newList<int> ;
for(inti=0;i<100;i++)
{
list.Add(i);
}

//AsParallel -并行运算
//AsSequential -串行运算
//AsOrdered -保持数据的原有顺序(AsSequential 指的是串行运算;AsOrdered 指的是如果在并行运算的前提下,它会把结果先缓存,然后排序,最后再把排序后的数据做输出)
//AsUnordered -可以不必保持数据的原有顺序
//WithDegreeOfParallelism -明确地指出需要使用多少个线程来完成工作
//WithCancellation(newCancellationTokenSource .Token)-指定一个CancellationToken类型的参数

ParallelQuerynums=fromnuminlist.AsParallel<int> .AsOrdered<int>
wherenum%10==0
selectnum;

foreach(varnuminnums)
{
Response.Write(num.ToString );
Response.Write('<br/>');
}

//聚合方法也可以做并行运算
Response.Write(list.AsParallel .Average .ToString );
Response.Write('<br/>');

//自定义聚合方法做并行运算的Demo(实现一个取集合的平均值的功能)
doublemyAggregateResult=list.AsParallel .Aggregate(
//聚合变量的初始值
0d,

//在每个数据分区上,计算此分区上的数据
//第一个参数:对应的数据分区的计算结果;第二个参数:对应的数据分区的每个数据项
(value,item)=>
{
doubleresult=value+item;
returnresult;
},

//根据每个数据分区上的计算结果,再次做计算
//第一个参数:全部数据的计算结果;第二个参数:每个数据分区上的计算结果
(value,data)=>
{
doubleresult=value+data;
returnresult;
},

//根据全部数据的计算结果再次计算,得到最终的聚合结果
(result)=>result/list.Count
);

Response.Write(myAggregateResult.ToString );
}
}
}

/*
运行结果:
0
10
20
30
40
50
60
70
80
90
49.5
49.5
*/

注:关于并行运算的实例可以参考
http://code.msdn.microsoft.com/ParExtSamples

OK
[源码下载]

热门