[英]Trying to understand multi-threading in C#
我正在嘗試了解多線程的基礎知識,所以我構建了一個小程序,提出了一些問題,我將感謝任何幫助:)
這是小程序:
class Program
{
public static int count;
public static int max;
static void Main(string[] args)
{
int t = 0;
DateTime Result;
Console.WriteLine("Enter Max Number : ");
max = int.Parse(Console.ReadLine());
Console.WriteLine("Enter Thread Number : ");
t = int.Parse(Console.ReadLine());
count = 0;
Result = DateTime.Now;
List<Thread> MyThreads = new List<Thread>();
for (int i = 1; i < 31; i++)
{
Thread Temp = new Thread(print);
Temp.Name = i.ToString();
MyThreads.Add(Temp);
}
foreach (Thread th in MyThreads)
th.Start();
while (count < max)
{
}
Console.WriteLine("Finish , Took : " + (DateTime.Now - Result).ToString() + " With : " + t + " Threads.");
Console.ReadLine();
}
public static void print()
{
while (count < max)
{
Console.WriteLine(Thread.CurrentThread.Name + " - " + count.ToString());
count++;
}
}
}
我通過一些測試運行檢查了這一點:
我將最大數字設為 100,似乎最快的執行時間是使用 2 個線程,這比使用 10 個線程的時間快 80%。
問題:
1) 線程 4-10 一次都不打印,怎么可能?
2)不應該更多的線程更快嗎?
我將最大數量設為 10000 並禁用了打印。
使用這種配置,5 個線程似乎是最快的。
為什么與第一次檢查相比有變化?
而且在這種配置(帶打印)中,所有線程都會打印幾次。 為什么這與僅打印幾個線程的第一次運行不同?
有沒有辦法讓所有線程一個一個打印? 在一條線上或類似的東西?
非常感謝您的幫助:)
您的代碼無疑是進入線程世界的第一步,而您剛剛經歷了第一個(許多)頭痛!
首先, static
可以讓您在線程之間共享一個變量,但它不是以線程安全的方式這樣做的。 這意味着您的count < max
表達式和count++
不能保證是最新的或線程之間的有效保護。 查看程序的 output max
僅為 10(在我的 8 處理器工作站上設置為 4):
T0 - 0
T0 - 1
T0 - 2
T0 - 3
T1 - 0 // wait T1 got count = 0 too!
T2 - 1 // and T2 got count = 1 too!
T2 - 6
T2 - 7
T2 - 8
T2 - 9
T0 - 4
T3 - 1 // and T3 got count = 1 too!
T1 - 5
對於您關於逐個打印每個線程的問題,我假設您正在嘗試協調對count
的訪問。 您可以使用同步原語(例如 C# 中的lock
語句)來完成此操作。 這是對您的代碼的天真修改,它將確保僅發生max
增量:
static object countLock = new object();
public static void printWithLock()
{
// loop forever
while(true)
{
// protect access to count using a static object
// now only 1 thread can use 'count' at a time
lock (countLock)
{
if (count >= max) return;
Console.WriteLine(Thread.CurrentThread.Name + " - " + count.ToString());
count++;
}
}
}
這個簡單的修改使您的程序在邏輯上正確,但也很慢。 該示例現在出現了一個新問題:鎖爭用。 現在每個線程都在爭奪對countLock
的訪問權。 我們已經使我們的程序線程安全,但沒有任何並行性的好處!
線程和並行性並不是特別容易正確處理,但值得慶幸的是,.Net 的最新版本帶有任務並行庫 (TPL)和並行 LINQ (PLINQ) 。
該庫的美妙之處在於轉換您當前的代碼是多么容易:
var sw = new Stopwatch();
sw.Start();
Enumerable.Range(0, max)
.AsParallel()
.ForAll(number =>
Console.WriteLine("T{0}: {1}",
Thread.CurrentThread.ManagedThreadId,
number));
Console.WriteLine("{0} ms elapsed", sw.ElapsedMilliseconds);
// Sample output from max = 10
//
// T9: 3
// T9: 4
// T9: 5
// T9: 6
// T9: 7
// T9: 8
// T9: 9
// T8: 1
// T7: 2
// T1: 0
// 30 ms elapsed
上面的 output 有趣地說明了為什么線程會為新用戶產生“意外結果”。 當線程並行執行時,它們可能會在不同的時間點完成代碼塊,或者一個線程可能比另一個線程快。 你永遠不會真正了解線程!
您的打印 function 遠非線程安全,這就是 4-10 不打印的原因。 所有線程共享相同的 max 和 count 變量。
更多線程會減慢您速度的原因可能是每次處理器更改每個線程之間的焦點時都會發生 state 更改。
此外,當您創建大量線程時,系統需要分配新線程。 大多數情況下,現在建議改用任務,因為它們是從系統管理的線程池中提取的。 因此不一定要分配。 創建一個獨特的新線程是相當昂貴的。
無論如何看看這里: http://msdn.microsoft.com/en-us/library/aa645740(VS.71).aspx
仔細看:
t = int.Parse(Console.ReadLine());
count = 0;
Result = DateTime.Now;
List<Thread> MyThreads = new List<Thread>();
for (int i = 1; i < 31; i++)
{
Thread Temp = new Thread(print);
Temp.Name = i.ToString();
MyThreads.Add(Temp);
}
我認為您錯過了一個變量t ( i < 31)。
在編寫代碼之前,您應該閱讀許多有關並行和多線程編程的書籍,因為編程語言只是一種工具。 祝你好運!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.