程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> 精進不休 .NET 4.0 (5) - C# 4.0 新特性之並行運算(Parallel)

精進不休 .NET 4.0 (5) - C# 4.0 新特性之並行運算(Parallel)

編輯:關於C#

介紹

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_Load(object sender, EventArgs e)
         {
             Normal();
             ParallelForDemo();
         }
         private void Normal()
         {
             DateTime dt = DateTime.Now;
             for (int i = 0; i < 20; i++)
             {
                 GetData(i);
             }
             Response.Write((DateTime.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.For(0, 20, (i) => { GetData(i); });
             Response.Write((DateTime.Now - dt).TotalMilliseconds.ToString());
             Response.Write("<br />");
         }
         private int GetData(int i)
         {
             System.Threading.Thread.Sleep(100);
             Response.Write(i.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_Load(object sender, EventArgs e)
         {
             InitData();
             Normal();
             ParallelForEachDemo();
         }
         private void InitData()
         {
             _data.Clear();
             for (int i = 0; i < 20; i++)
             {
                 _data.Add(i);
             }
         }
         private void Normal()
         {
             DateTime dt = DateTime.Now;
             for (int i = 0; i < 20; i++)
             {
                 GetData(i);
             }
             Response.Write((DateTime.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) => { GetData(index); });
             Response.Write((DateTime.Now - dt).TotalMilliseconds.ToString());
             Response.Write("<br />");
         }
         private int GetData(int i)
         {
             System.Threading.Thread.Sleep(100);
             Response.Write(i.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_Load(object sender, EventArgs e)
         {
             var tasks = new Action[] { () => Task1(), () => Task2(), () => Task3()  };
             // System.Threading.Tasks.Parallel.Invoke - 並行調用多個任務
             System.Threading.Tasks.Parallel.Invoke(tasks);
         }
         private void Task1()
         {
             Thread.Sleep(3000);
             Response.Write("Task1 - " + "ThreadId:" + Thread.CurrentThread.ManagedThreadId.ToString () + " - " + DateTime.Now.ToString("HH:mm:ss"));
             Response.Write("<br />");
         }
         private void Task2()
         {
             System.Threading.Thread.Sleep(3000);
             Response.Write("Task2 - " + "ThreadId:" + Thread.CurrentThread.ManagedThreadId.ToString () + " - " + DateTime.Now.ToString("HH:mm:ss"));
             Response.Write("<br />");
         }
         private void Task3()
         {
             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 - 任務,基於線程池。其使我們對並行編程變得更簡單,且不用關心底層是怎麼實現的
*/
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_Load(object 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.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
             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 = delegate(object state)
             {
                 return 1.0;
             };
             Task<long> tsk = new Task<long>(fun, "state");
             tsk.Start();
             Response.Write(tsk.Result.ToString()); 
             */
         }
       
         private void Task1(CancellationToken token)
         {
             // 每隔 1 秒執行一次,直到此任務收到了取消的請求
             // 注意:雖然此處是其他線程要向主線程(UI線程)上輸出信息,但因為使用了 Task ,所以不用做任 何處理
             while (!token.IsCancellationRequested)
             {
                 Response.Write("Task1 - " + "ThreadId: " +  Thread.CurrentThread.ManagedThreadId.ToString());
                 Response.Write("<br />");
                 Thread.Sleep(1000);
             }
         }
         private void Task2(CancellationToken token)
         {
             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 - 用於對內存中的數據做並行運算,也就是說其只支持 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_Load(object sender, EventArgs e)
         {
             List<int> list = new List<int>();
             for (int i = 0; i < 100; i++)
             {
                 list.Add(i);
             }
             // AsParallel() - 並行運算
             // AsSequential() - 串行運算
             // AsOrdered() - 保持數據的原有順序(AsSequential()指的是串行運算;AsOrdered()指的是如果在 並行運算的前提下,它會把結果先緩存,然後排序,最後再把排序後的數據做輸出)
             // AsUnordered() - 可以不必保持數據的原有順序
             // WithDegreeOfParallelism() - 明確地指出需要使用多少個線程來完成工作
             // WithCancellation(new 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.Write(num.ToString());
                 Response.Write("<br />");
             }
             // 聚合方法也可以做並行運算
             Response.Write(list.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.Write(myAggregateResult.ToString());
         } 
     }
}
/*
運行結果:
0
10
20
30
40
50
60
70
80
90
49.5
49.5
*/

注:關於並行運算的實例可以參考

http://code.msdn.microsoft.com/ParExtSamples

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved