2011-07-05 20 views
4

我想了解的基礎知識,多線程,因此我建立了一個小程序,提出了幾個問題,我會感謝任何幫助:)試圖瞭解在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個線程是快80%比10個線程的時間要多。

問題:

1)主題4-10不打印,甚至有一段時間,這怎麼可能呢?

2)不應該有更多的線程更快?

我做了最大數字10000和禁用打印。

有了這個配置,5個線程似乎是最快的。

爲什麼與第一次檢查相比有變化?

而且在此配置中(打印時),所有線程都打印幾次。爲什麼與只有少量線程打印的第一次運行不同?

是否有辦法讓所有線程一個一個的打印?在一行或類似的東西?

非常感謝您的幫助:)

+1

請勿直接使用線程。這看起來可能違反直覺,但請相信我:他們會讓你生氣。如果我是你,我會研究C#的任務並行庫(TPL)。 –

+0

[同步]快速概述(http://en.wikipedia.org/wiki/Synchronization_%28computer_science%29)。 – ChaosPandion

+3

這種測試不適合理解性能問題。你有很多閱讀要做。 –

回答

0

你的打印功能還遠遠沒有線程安全的,這就是爲什麼4-10不打印。所有線程共享相同的最大和計數變量。

更多線程降低速度的原因可能是每次處理器在每個線程之間改變焦點時發生的狀態更改。

此外,當您創建大量線程時,系統需要分配新線程。大多數情況下,現在建議使用Tasks,因爲它們是從系統託管的線程池中提取的。因此不一定必須分配。創建一個獨特的新線程相當昂貴。

看看這裏無論如何:http://msdn.microsoft.com/en-us/library/aa645740(VS.71).aspx

7

你的代碼肯定是第一步到線程的世界,你剛剛經歷了第一次頭痛(很多)!

首先,static可以使您份額線程之間的變量,但它並沒有在線程安全的方式這樣做。這意味着您的count < max表達式和count++不保證是最新的或線程之間的有效後衛。看看你的程序的輸出時max只有10(T爲4,我的8個處理器的工作站上):

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來與Task Parallel Library (TPL)Parallel 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 

輸出上面就是爲什麼線程產生「意外結果」爲新用戶一個有趣的例證。當線程並行執行時,它們可能會在不同的時間點完成代碼塊,或者一個線程可能比另一個線程更快。你永遠不會知道線程!

+0

+1我真的很喜歡第一行 –

+0

+1詳細信息! –

0

看carefuly:

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

我想你錯過了一個變量(我< 31)。

在編寫代碼之前,您應該閱讀許多有關並行和多線程編程的書籍,因爲編程語言只是一個工具。祝你好運!