[索引頁]
[×××]
精進不休 .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