這個範例,耗費10.92秒,其實可以做得更好…
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
internal class Program
{
static byte[] values = new byte[500000000];
static void GenerateInts()
{
var rnd = new Random();
for (int i = 0; i < values.Length ; i++) {
values[i] = (byte)rnd.Next(10);
}
}
static void Main(string[] args)
{
GenerateInts(); //產生很多整數
Console.WriteLine("Summing...");
//使用Stopwatch來看花了多少時間加總
Stopwatch watch = new Stopwatch();
watch.Start();//開始計時
long total = 0;
for (int i = 0; i < values.Length; i++) {
total += values[i];
}
watch.Stop(); //結束計時
Console.WriteLine($"Total value is: {total}");
Console.WriteLine($"Time to sum: {watch.Elapsed}");
//Console.WriteLine($"Time to sum: {watch.ElapsedMilliseconds/1000} 秒");
}
}
/* 執行結果
Summing...
Total value is: 2249935218
Time to sum: 00:00:10.9200492
*/
如果我有8個CPU,我希望看到所有8個CPU的執行緒都在啟動努力的運作
10.92秒/8的話,所以我想建立8個執行緒,讓程式跑得更快得到結果
假設我有很長、無數個數字… 把它分成偶數8塊,然後把它們送走, 這不一定是很好的算法,但它是一個相當不錯的算法XD
它不是很好的算法的原因是:有些執行緒會先比其他執行緒完成, 而那些在其他執行緒之前完成的執行緒,理論上可以彌補其他執行緒的無法接管的不足
但無論如何,我們都將其平均分配8塊…
所有執行緒都從陣列中讀取,沒有一個執行緒寫入陣列
所以每個人都想讀的話,這是安全的,
讀掉它是讓執行緒同步
問題是,當我們寫入時,你能想到我們正在寫入這個陣列時,而其他執行緒正在讀取…
我們正在生成隨機數,而其他執行緒正在嘗試將它們相加,並且一些隨機數還沒有準備好…
那麼我們還有一些的同步問題,還有一些問題需要協調:
- 該執行緒需要知道它正在執行陣列這一部分
- 每個執行緒都應該報告其總計
宣告變數,存放每個執行緒報告的總計、要讀取多少數據的大小
- 宣告變數
portionResults,用來存放每個執行緒回報的加總 在主執行緒
Main()中,初始化portionResults陣列,長度為「CPU處理器核心數」
使用Environment.ProcessorCount取得「CPU處理器核心數」- 宣告變數
portionSize,表示每個執行緒所擁有值的大小 - 在主執行緒
Main()中,設置它的大小(平均分配):擁有的所有數字 / 挪有的處理器的數量
1
2
3
4
5
6
7
//每個執行緒回報的加總
static long[] portionResults;
portionResults = new long[Environment.ProcessorCount]; //長度為該電腦的CPU處理器核心數(有8個cpu就會保存8個值)
//每個執行緒所擁有值的大小(也就是要讀取多少的數據,平均分配)
static int portionSize;
portionSize = values.Length / Environment.ProcessorCount; //大小(平均分配): 所有數字量/挪有的處理器的數量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
internal class Program
{
static byte[] values = new byte[500000000]; //放置隨機產生的很多的數字
static long[] portionResults; //存放每個執行緒回報的加總
static int portionSize; //每個執行緒所擁有值的大小(也就是要讀取多少的數據)
//隨機產生很多數字
static void GenerateInts()
{
var rnd = new Random(); //隨機數
for (int i = 0; i < values.Length ; i++) {
values[i] = (byte)rnd.Next(10); //因為是存放到byte陣列,所以值的範圍是0~9
}
}
static void Main(string[] args)
{
//長度為該電腦的CPU處理器核心數(有8個cpu就會保存8個值)
portionResults = new long[Environment.ProcessorCount];
//大小(平均分配): 所有數字量/挪有的處理器的數量
portionSize = values.Length / Environment.ProcessorCount;
GenerateInts(); //產生很多整數
Console.WriteLine("Summing...");
//使用Stopwatch來看花了多少時間加總
Stopwatch watch = new Stopwatch();
watch.Start();//開始計時
long total = 0;
for (int i = 0; i < values.Length; i++) {
total += values[i];
}
watch.Stop(); //結束計時
Console.WriteLine($"Total value is: {total}");
Console.WriteLine($"Time to sum: {watch.Elapsed}");
//Console.WriteLine($"Time to sum: {watch.ElapsedMilliseconds/1000} 秒");
}
}
求和方法:所有執行緒都執行這方法
加一個方法SumYourPortion(),
使用之前所提到的-參數化線程啟動 thread.Start(object? parameter)
1
2
3
4
5
6
//參數化執行緒啟動
static void SumYourPortion(object portionNumber)
{
//加總
//存放加總結果
}
每個執行緒都會調用這一個方法去做加總,並存放結果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//參數化執行緒-每個線程都會執行該方法,加總自己部分的數字
static void SumYourPortion(object portionNumber)
{
long sum = 0;
int portionNumberAsInt = (int)portionNumber;
//加總
for (int i = portionNumberAsInt * portionSize; i < portionNumberAsInt * portionSize + portionSize; i++) {
sum += values[i];
}
//存放加總結果
portionResults[portionNumberAsInt] = sum;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
internal class Program
{
static byte[] values = new byte[500000000]; //放置隨機產生的很多的數字
static long[] portionResults; //存放每個執行緒回報的加總
static int portionSize; //每個執行緒所擁有值的大小(也就是要讀取多少的數據)
static void GenerateInts()
{
var rnd = new Random();
for (int i = 0; i < values.Length; i++)
{
values[i] = (byte)rnd.Next(10);
}
}
//參數化執行緒-每個線程都會執行該方法,加總自己部分的數字
static void SumYourPortion(object portionNumber)
{
long sum = 0;
int portionNumberAsInt = (int)portionNumber;
//加總
for (int i = portionNumberAsInt * portionSize; i < portionNumberAsInt * portionSize + portionSize; i++)
{
sum += values[i];
}
//存放加總結果
portionResults[portionNumberAsInt] = sum;
}
static void Main(string[] args)
{
//長度為該電腦的CPU處理器核心數(有8個cpu就會保存8個值)
portionResults = new long[Environment.ProcessorCount];
//大小: 所有數字 /挪有的處理器的數量
portionSize = values.Length / Environment.ProcessorCount;
GenerateInts(); //產生很多整數
Console.WriteLine("Summing...");
//使用Stopwatch來看花了多少時間加總
Stopwatch watch = new Stopwatch();
watch.Start();//開始計時
long total = 0;
for (int i = 0; i < values.Length; i++)
{
total += values[i];
}
watch.Stop(); //結束計時
Console.WriteLine($"Total value is: {total}");
Console.WriteLine($"Time to sum: {watch.Elapsed}");
//Console.WriteLine($"Time to sum: {watch.ElapsedMilliseconds/1000} 秒");
}
}
Threading - Divide and Conquer Example Part 2
[C# 筆記] Threading - C# Multiple Threads [C# 筆記] Threading - Divide and Conquer Example Part 1
[C# 筆記] Threading - Divide and Conquer Example Part 2