精进不休 .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
代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace CSharp.Parallel
{
public partial class ParallelFor : System.Web.UI.Page
{
protected void Page_Loadobject sender, EventArgs e)
{
Normal);
ParallelForDemo);
}
private void Normal)
{
DateTime dt = DateTime.Now;
for int i = 0; i < 20; i++)
{
GetDatai);
}
Response.WriteDateTime.Now – dt).TotalMilliseconds.ToString));
Response.Write”<br />”);
Response.Write”<br />”);
}
private void ParallelForDemo)
{
DateTime dt = DateTime.Now;
// System.Threading.Tasks.Parallel.For – for 循环的并行运算
System.Threading.Tasks.Parallel.For0, 20, i) => { GetDatai); });
Response.WriteDateTime.Now – dt).TotalMilliseconds.ToString));
Response.Write”<br />”);
}
private int GetDataint i)
{
System.Threading.Thread.Sleep100);
Response.Writei.ToString));
Response.Write”<br />”);
return i;
}
}
}
/*
运行结果:
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
代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace CSharp.Parallel
{
public partial class ParallelForEach : System.Web.UI.Page
{
private List<int> _data = new List<int>);
protected void Page_Loadobject sender, EventArgs e)
{
InitData);
Normal);
ParallelForEachDemo);
}
private void InitData)
{
_data.Clear);
for int i = 0; i < 20; i++)
{
_data.Addi);
}
}
private void Normal)
{
DateTime dt = DateTime.Now;
for int i = 0; i < 20; i++)
{
GetDatai);
}
Response.WriteDateTime.Now – dt).TotalMilliseconds.ToString));
Response.Write”<br />”);
Response.Write”<br />”);
}
private void ParallelForEachDemo)
{
DateTime dt = DateTime.Now;
// System.Threading.Tasks.Parallel.ForEach – foreach 循环的并行运算
System.Threading.Tasks.Parallel.ForEach_data, index) => { GetDataindex); });
Response.WriteDateTime.Now – dt).TotalMilliseconds.ToString));
Response.Write”<br />”);
}
private int GetDataint i)
{
System.Threading.Thread.Sleep100);
Response.Writei.ToString));
Response.Write”<br />”);
return i;
}
}
}
/*
运行结果:
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
代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Threading;
namespace CSharp.Parallel
{
public partial class ParallelInvoke : System.Web.UI.Page
{
protected void Page_Loadobject sender, EventArgs e)
{
var tasks = new Action[] { ) => Task1), ) => Task2), ) => Task3) };
// System.Threading.Tasks.Parallel.Invoke – 并行调用多个任务
System.Threading.Tasks.Parallel.Invoketasks);
}
private void Task1)
{
Thread.Sleep3000);
Response.Write”Task1 – ” + “ThreadId:” + Thread.CurrentThread.ManagedThreadId.ToString) + ” – ” + DateTime.Now.ToString”HH:mm:ss”));
Response.Write”<br />”);
}
private void Task2)
{
System.Threading.Thread.Sleep3000);
Response.Write”Task2 – ” + “ThreadId:” + Thread.CurrentThread.ManagedThreadId.ToString) + ” – ” + DateTime.Now.ToString”HH:mm:ss”));
Response.Write”<br />”);
}
private void Task3)
{
System.Threading.Thread.Sleep3000);
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 – 任务,基于线程池。其使我们对并行编程变得更简单,且不用关心底层是怎么实现的
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Threading;
using System.Threading.Tasks;
namespace CSharp.Parallel
{
public partial class ParallelTask : System.Web.UI.Page
{
protected void Page_Loadobject sender, EventArgs e)
{
/*
* CancellationTokenSource – 取消任务的操作需要用到的一个类
* Token – 一个 CancellationToken 类型的对象,用于通知取消指定的操作
* IsCancellationRequested – 是否收到了取消操作的请求
* Cancel) – 结束任务的执行
* ParallelOptions – 并行运算选项
* CancellationToken – 设置一个 Token,用于取消任务时的相关操作
* MaxDegreeOfParallelism – 指定一个并行循环最多可以使用多少个线程
*/
CancellationTokenSource cts = new CancellationTokenSource);
ParallelOptions pOption = new ParallelOptions) { CancellationToken = cts.Token };
pOption.MaxDegreeOfParallelism = 10;
Response.Write”开始执行,3.5 秒后结束”);
Response.Write”<br />”);
/*
* Task – 任务类
* Factory.StartNew) – 创建并开始一个或一批新任务
* ContinueWith) – 此任务完成后执行指定的另一个任务
* AsyncState – 此任务的上下文对象
* Wait) – 阻塞,直到任务完成
*/
Task task0 = Task.Factory.StartNew) =>
{
Thread.Sleep3500);
cts.Cancel);
Response.Write”结束”);
Response.Write”<br />”);
});
// 通过 System.Threading.Tasks.Parallel.Invoke 执行任务的时候,可以加入 ParallelOptions 参数,用于对此并行运算做一些配置
System.Threading.Tasks.Parallel.InvokepOption,
) => Task1pOption.CancellationToken),
) => Task2pOption.CancellationToken));
/*
* 一个 Task 内可以包含多个 Task
Task tasks = new Task) =>
{
Task.Factory.StartNew) => Method));
Task.Factory.StartNew) => Method2));
Task.Factory.StartNew) => Method3));
});
tasks.Start);
// 阻塞,直到整个任务完成
tasks.Wait);
*/
/*
* 带返回值的 Task
Func<object, long> fun = delegateobject state)
{
return 1.0;
};
Task<long> tsk = new Task<long>fun, “state”);
tsk.Start);
Response.Writetsk.Result.ToString));
*/
}
private void Task1CancellationToken token)
{
// 每隔 1 秒执行一次,直到此任务收到了取消的请求
// 注意:虽然此处是其他线程要向主线程(UI线程)上输出信息,但因为使用了 Task ,所以不用做任何处理
while !token.IsCancellationRequested)
{
Response.Write”Task1 – ” + “ThreadId: ” + Thread.CurrentThread.ManagedThreadId.ToString));
Response.Write”<br />”);
Thread.Sleep1000);
}
}
private void Task2CancellationToken token)
{
while !token.IsCancellationRequested)
{
Response.Write”Task2 – ” + “ThreadId: ” + Thread.CurrentThread.ManagedThreadId.ToString));
Response.Write”<br />”);
Thread.Sleep1000);
}
}
}
}
/*
运行结果:
开始执行,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 – 用于对内存中的数据做并行运算,也就是说其只支持 LINQ to Object 的并行运算
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace CSharp.Parallel
{
public partial class ParallelPLINQ : System.Web.UI.Page
{
protected void Page_Loadobject sender, EventArgs e)
{
List<int> list = new List<int>);
for int i = 0; i < 100; i++)
{
list.Addi);
}
// AsParallel) – 并行运算
// AsSequential) – 串行运算
// AsOrdered) – 保持数据的原有顺序(AsSequential)指的是串行运算;AsOrdered)指的是如果在并行运算的前提下,它会把结果先缓存,然后排序,最后再把排序后的数据做输出)
// AsUnordered) – 可以不必保持数据的原有顺序
// WithDegreeOfParallelism) – 明确地指出需要使用多少个线程来完成工作
// WithCancellationnew CancellationTokenSource).Token) – 指定一个 CancellationToken 类型的参数
ParallelQuery nums = from num in list.AsParallel<int>).AsOrdered<int>)
where num % 10 == 0
select num;
foreach var num in nums)
{
Response.Writenum.ToString));
Response.Write”<br />”);
}
// 聚合方法也可以做并行运算
Response.Writelist.AsParallel).Average).ToString));
Response.Write”<br />”);
// 自定义聚合方法做并行运算的 Demo(实现一个取集合的平均值的功能)
double myAggregateResult = list.AsParallel).Aggregate
// 聚合变量的初始值
0d,
// 在每个数据分区上,计算此分区上的数据
// 第一个参数:对应的数据分区的计算结果;第二个参数:对应的数据分区的每个数据项
value, item) =>
{
double result = value + item;
return result;
},
// 根据每个数据分区上的计算结果,再次做计算
// 第一个参数:全部数据的计算结果;第二个参数:每个数据分区上的计算结果
value, data) =>
{
double result = value + data;
return result;
},
// 根据全部数据的计算结果再次计算,得到最终的聚合结果
result) => result / list.Count
);
Response.WritemyAggregateResult.ToString));
}
}
}
/*
运行结果:
0
10
20
30
40
50
60
70
80
90
49.5
49.5
*/
注:关于并行运算的实例可以参考
http://code.msdn.microsoft.com/ParExtSamples
OK
[源码下载]