天天看點

精進不休 .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 的并行運算

示例

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

        {

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 />");

void ParallelForDemo() void ParallelForDemo()

                        // System.Threading.Tasks.Parallel.For - for 循環的并行運算

                        System.Threading.Tasks.Parallel.For(0, 20, (i) => { GetData(i); });

int GetData() int GetData(int i)

                        System.Threading.Thread.Sleep(100);

                        Response.Write(i.ToString());

                        return i;

        }

}

/*

運作結果:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

2000.0514

300.0077

*/

2、Parallel.ForEach 的 Demo

Parallel/ParallelForEach.aspx.cs

        public partial class ParallelForEach : System.Web.UI.Page

List<int> _data = new List<int>() List<int> _data = new List<int>();

                        InitData();

                        ParallelForEachDemo();

void InitData() void InitData()

                        _data.Clear();

                                _data.Add(i);

void ParallelForEachDemo() void ParallelForEachDemo()

                        // System.Threading.Tasks.Parallel.ForEach - foreach 循環的并行運算

                        System.Threading.Tasks.Parallel.ForEach(_data, (index) => { GetData(index); });

600.0154

3、Parallel.Invoke 的 Demo

Parallel/ParallelInvoke.aspx.cs

using System.Threading;

        public partial class ParallelInvoke : System.Web.UI.Page

                        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"));

void Task2() void Task2()

                        System.Threading.Thread.Sleep(3000);

                        Response.Write("Task2 - " + "ThreadId:" + Thread.CurrentThread.ManagedThreadId.ToString() + " - " + DateTime.Now.ToString("HH:mm:ss"));

void Task3() void Task3()

                        Response.Write("Task3 - " + "ThreadId:" + Thread.CurrentThread.ManagedThreadId.ToString() + " - " + DateTime.Now.ToString("HH:mm:ss"));

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.Threading.Tasks;

{        

        public partial class ParallelTask : System.Web.UI.Page

                        /*

                         * 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 秒後結束");

                         * 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());

                                Thread.Sleep(1000);

void Task2() void Task2(CancellationToken token)

                                Response.Write("Task2 - " + "ThreadId: " + Thread.CurrentThread.ManagedThreadId.ToString());

開始執行,3.5 秒後結束

Task2 - ThreadId: 6

Task1 - ThreadId: 48

結束

5、PLINQ 的 Demo

Parallel/ParallelPLINQ.aspx.cs

PLINQ - 用于對記憶體中的資料做并行運算,也就是說其隻支援 LINQ to Object 的并行運算

        public partial class ParallelPLINQ : System.Web.UI.Page

                        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(list.AsParallel().Average().ToString());

                        // 自定義聚合方法做并行運算的 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());

                }    

20

30

40

50

60

70

80

90

49.5

49.5    

注:關于并行運算的執行個體可以參考

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

OK