博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

并行操作(Parallel) 笔记

Posted on 2012-02-27 13:58  蔡豹  阅读(452)  评论(0)    收藏  举报

在命名空间System.Threading.Tasks下,有一个静态类Parallel,Parallel主要提供了3个有用的方法:For、ForEach、Invoke。

并行操作遍历集合不是顺序的,如果输出必须是同步的、有顺序的,建议不要使用Parallel类。

下面是用Parallel中的For,ForEach与普通的Foreach循环对集合操作的运行时间进行了一下比较:

首先 生成一千万的测试数据存入集合,集合中是随机生成的字符串,要做的就从集合中查找包含字符串"a"或"abc"所消耗的时间(单位:毫秒(ms))。

 1         /// <summary>
2 /// 生成测试数据
3 /// </summary>
4 /// <returns></returns>
5 public static List<string> GetTestData()
6 {
7
8 for (int i = 0; i < 10000000; i++) {
9 testData.Add(RandChars(4));
10 }
11 return testData;
12 }

其中方法RandChars用来产生随机字符串。

下面写三个方法用来查找,分别对应Parallel中的For,Foreach,普通的Foreach,如代码:

  /// <summary>
/// 普通的foreach循环
/// </summary>
public static void Foreach()
{
List<string> resultData = new List<string>();

foreach (string s in testData)
{
if (s.Contains("a") || s.Contains("abc")) {
resultData.Add(s);
}

}
}
/// <summary>
/// Parallel.For
/// </summary>
public static void ParallerFor()
{
ConcurrentStack<string> resultData = new ConcurrentStack<string>();

Parallel.For(0, testData.Count - 1, (i, loopState) =>
{
string s = testData[i];
if (s.Contains("a") || s.Contains("abc"))
{
resultData.Push(s);
}

});
}
/// <summary>
/// Parallel.ForEach
/// </summary>
public static void ParallerForEach()
{
ConcurrentStack<string> resultData = new ConcurrentStack<string>();
Parallel.ForEach(testData,(s,loopState)=>
{

if (s.Contains("a") || s.Contains("abc"))
{
resultData.Push(s);
}

});
}

方法ParallerForEach和ParallerFor中用来存放结果的集合,此处用的是System.Collections.Concurrent命名空间中的ConcurrentStack,因为.Net 3.5 之前所提供的所有 Collections 都不是 thread-safe 的,必须使用.Net 4.0 System.Collections.Concurrent下的泛型。

顺便说一下Parallel.For的用法

public static ParallelLoopResult For(int fromInclusive, int toExclusive, Action<int> body);  
public static ParallelLoopResult For(int fromInclusive, int toExclusive, Action<int, ParallelLoopState> body); 
这是最常用的重载,其中 fromInclusive 是起始元素索引、toExclusive 是结束元素索引,用法与普通的For循环一样, 
其中 Action<int,ParalleLoopState> 表示要执行的delegate

最后 开始执行这三个方法,分别记录三个方法查找字符所消耗的时间,执行20次,最后看其运行20次所耗的平均时间

 1     static void Main(string[] args)
2 {
3
4 GetTestData();//初始化测试数据
5 long ms = 0, ms1 = 0, ms2 = 0;
6 long tms = 0, tms1 = 0, tms2 = 0;
7 Stopwatch sw = new Stopwatch();
8 for (int z = 0; z < 20; z++)
9 {
10 sw.Start();
11 Foreach();//普通的Foreach
12 ms = sw.ElapsedMilliseconds;
13
14 sw.Reset();
15 sw.Start();
16 ParallerFor();//Parallel中的For
17 ms1 = sw.ElapsedMilliseconds;
18
19 sw.Reset();
20 sw.Start();
21 ParallerForEach();//Parallel中的Foreach
22 ms2 = sw.ElapsedMilliseconds;
23
24 sw.Reset();
25 Console.WriteLine(string.Format("foreach:{0},Parallel.for:{1},Parallel.foreach:{2}", ms, ms1, ms2));
26 tms += ms;
27 tms1 += ms1;
28 tms2 += ms2;
29 }
30 //输出20次的平均时间
31 Console.WriteLine(string.Format("Avg foreach:{0},Parallel.for:{1},Parallel.foreach:{2}", tms/20, tms1/20, tms2/20));
32 }


输出结果: