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

[索引頁]
[×××]


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


做者: webabcd


介紹
C# 4.0 的新特性之並行運算
  • Parallel.For - for 循環的並行運算 
  • Parallel.ForEach - foreach 循環的並行運算 
  • Parallel.Invoke - 並行調用多個任務 
  • Task - 任務,基於線程池。其使咱們對並行編程變得更簡單,且不用關心底層是怎麼實現的
  • PLINQ - 用於對內存中的數據作並行運算,也就是說其只支持 LINQ to Object 的並行運算


示例
一、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
        {
void Page_Load() void Page_Load(object sender, EventArgs e)
                {
                        Normal();
                        ParallelForDemo();
                }

void Normal() 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 />");
                }

void ParallelForDemo() 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 />");
                }

int GetData() 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
*/
 
 
二、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
        {
List<int> _data = new List<int>() List<int> _data = new List<int>();

void Page_Load() void Page_Load(object sender, EventArgs e)
                {
                        InitData();

                        Normal();
                        ParallelForEachDemo();
                }

void InitData() void InitData()
                {
                        _data.Clear();
                         for (int i = 0; i < 20; i++)
                        {
                                _data.Add(i);
                        }
                }

void Normal() 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 />");
                }

void ParallelForEachDemo() 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 />");
                }

int GetData() 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
*/
 
 
三、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
        {
void Page_Load() 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);
                }

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

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

void Task3() 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
*/
 
 
四、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
        {
void Page_Load() 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());    
                        */
                }
                
void Task1() void Task1(CancellationToken token)
                {
                        // 每隔 1 秒執行一次,直到此任務收到了取消的請求
                        // 注意:雖然此處是其餘線程要向主線程(UI線程)上輸出信息,但由於使用了 Task ,因此不用作任何處理
                         while (!token.IsCancellationRequested)
                        {
                                Response.Write( "Task1 - " + "ThreadId: " + Thread.CurrentThread.ManagedThreadId.ToString());
                                Response.Write( "<br />");
                                Thread.Sleep(1000);
                        }

                }
void Task2() 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
結束
*/
 
 
五、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
        {
void Page_Load() 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


OK
[×××]
相關文章
相關標籤/搜索