簡體   English   中英

線程示例 C#

[英]Threading example C#

我在網上找到了這本書。 Joseph 的 C# 線程。 我試過它的例子

class ThreadTest
{
    static void Main()
    {
        Thread t = new Thread(WriteY);          // Kick off a new thread
        t.Start();                               // running WriteY()

        // Simultaneously, do something on the main thread.
        for (int i = 0; i < 10000000; i++) Console.Write("x");
        Console.ReadLine();
    }
    static void WriteY()
    {
        for (int i = 0; i < 10000000; i++) Console.Write("y");
    }
}

問題是,當我運行這個程序時(我在 for 循環中給出了更高的值來觀察)我的 CPU 利用率堅持 100%。 我不想要這個,我的意思是,無論如何要減少以減少這個程序的 CPU 密集度? 我只是多線程概念的新手,所以我想我應該提前詢問。

如果您可以同時使用多個資源,則多線程可以改善您的應用程序。 例如,如果您有多個核心或多個CPU,我相信上面的示例應該會更好。

或者,如果您有一個使用CPU的線程,以及另一個同時使用該磁盤的線程,如果您使用多線程,它也會表現更好。

但是,如果您有一個CPU或一個單核,則上面的示例將無法更好地執行。 它會表現得更糟。

你無法降低利用率,因為你使用的是兩個線程(很可能是在雙核上),這兩個線程都是工作密集型的(它們循環並打印一些東西)。 也許減少線程優先級可能有所幫助,但我認為這不是這個例子的重點。

WriteY函數中的循環將盡快執行。 所以它將使用100%的CPU。 如果您希望它不那么耗費資源,那么您可以做兩件事:

  • 更改線程的優先級。 這樣,您的應用程序仍將使用100%的CPU,但如果另一個線程需要CPU資源,該線程將“減速”

  • 在WriteY函數中添加暫停:

     static void WriteY() { for (int i = 0; i < 10000000; i++) { Console.Write("y"); Thread.Sleep(100); } } 

Console.Write之后添加Thread.Sleep(num of millseconds)因為循環將完全利用cpu。

class ThreadTest 
{
     static void Main()
     {
         Thread t = new Thread(WriteY);
          // Kick off a new thread
         t.Start();
         // running WriteY()
         // Simultaneously, do something on the main thread.
         for (int i = 0; i < 10000000; i++)
         {
              Console.Write("x");
              Console.ReadLine();     
         }
     }     

    static void WriteY()
    {
         for (int i = 0; i < 10000000; i++) 
         {
               Console.Write("y");
               Thread.Sleep(1000); // let the thread `sleep` for one seconds before running.     
         } 
    } 
}

更新

好吧,你可以使用這個例子 ,如果你有多個核心,使用.Net 4 Parallel Extensions。

var result = from ipaddress in new[]
{
  "111.11.11.11",
  "22.22.22.22",
  "22.33.44.55"
  /* or pulled from whatever source */
}
.AsParallel().WithDegreeOfParallelism(6)
let p = new Ping().Send(IPAddress.Parse(ipaddress))
select new
{
  site,
  Result = p.Status,
  Time = p.RoundtripTime
}

/* process the information you got*/

首先,嘗試該程序的單線程等效項。 您可能會發現它也使用了100%的核心,甚至可能更多(假設您有多個核心,顯然超過100%/ 1是不可能的)。 示例代碼是示例代碼,並且在所有方面通常都不現實。

很多問題與100%的CPU利用率有關,因此可能會導致認為100%CPU ==壞東西。

實際上,100%的CPU ==昂貴的電子產品正在為你付錢做它的工作!

不幸的是,你付錢給它做的是遵循計算機程序中的指示。 如果計算機程序告訴它進入一個緊密的無限循環,那么它將花費盡可能接近100%的CPU(不同的調度程序在讓其他線程做其他事情時比其他程序更好)。 這是100%CPU的經典壞情況。 是的,它正在做它被告知的事情,但它被告知是無意義的,永遠不會走到盡頭,遺憾的是它是如此“高效”,以至於它真的很好地保持其他線程不受影響。

讓我們考慮另一個案例:

  1. 將要完成的工作量是有限的 - 在某些時候它已經完成了。
  2. 你沒有其他任何你想要的計算機。

這里越接近100%越好。 每個%低於100表示​​CPU等待某事發生。 如果我們可以讓“某些東西”更快地發生(可能更快的磁盤和內存),或者如果我們可以讓CPU處理問題的另一部分,那么我們將更快地完成我們的完成點。 因此,如果我們用多線程方法替換代碼,讓它在另一個線程等待時利用CPU,並且如果這樣做的開銷沒有抵消好處,那么我們就會獲得性能提升。 (此外,這意味着我們可以使用x%的所有核心替換使用x%的一個核心的東西,並且因此更快)。

實際上,我們只需要做幾次特定的工作,而不關心其他任何事情。 事實上,即使我們這樣做,我們也會在此期間被UI所嚇倒,忘記“讓它看起來不被鎖定而且永遠不會回來”屬於“其他任何事物”的范疇。

所以。 在現實世界中,我們做什么。

首先,我們檢查一個真正的問題。 如果它暫時處於100%CPU,但是所有東西(包括其他進程)都可以完成它們的工作,那實際上很好 - CPU總是做一些事情,但這並不是因為一堆線程搞砸了它,它是因為所有要做的事情的線程都要去做。 快樂的時光。

然后我們檢查我們實際上會遇到這種情況。 如果你有一個使用ax線程的多線程方法,每個方法都會花費大部分時間等待I / O,那么它們就不會遵循與你的例子相同的模式。 如果性能對於該特定任務至關重要,那么您實際上可能正在尋找重構它的方法,以便您可以在問題上拋出更多線程,因此CPU有更多時間做有用的事情,而當每個線程都在等待時更少一些東西。

如果我們發現流程中的CPU利用率損害了所有內容,那么我們可以做一些不同的事情:

  1. 只需使用一個線程。 除了所有其他過程的考慮因素之外,盡可能快地完成此過程是否真的很重要? 很多事情我們實際上並不想要這個。 真的是最重要的事情。

  2. 降低線程優先級。 我們考慮這只是一個完成答案的答案。 這樣做有一些相當微妙的風險,最終會導致“優先級倒置”(簡而言之,高優先級線程最終會等待低優先級線程,這意味着只有低優先級線程才能運行,而你在實踐中得到與你想要的完全相反的優先級。

  3. 使用YieldSleep手動放棄CPU。 但是,如果你正在考慮這個問題,那么你必須問“這有什么不同,只是隨意引入低效率?”。 如果你沒有一個好的答案,那么單線程可能再次提供機器CPU的最佳總使用率而不是多線程。

  4. 是否需要運行所有的時間。 你說上面有關於監控的事情。 您真正需要的響應速度有多快? 如果用多線程方法檢查你正在監視的所有內容需要0.01秒,並且你很高興在它發生2秒后知道它,那么你的進程的效率是它需要的200倍,以犧牲其他過程為代價。 從計時器中解決問題。 (如果它需要一個單線程.5秒來完成所有這些,那么再次,為什么要多?)

以上所有內容僅考慮使用多線程來更快地完成特定任務的情況。 值得注意的是,這只是整個多線程模式范圍的一個子集。 例如,如果您采用上面的計時器方法,但是使用單個線程然后執行工作,但是您在一個也在做其他事情的過程中這樣做,那么這仍然算作多線程; 有一個線程正在執行該任務,而其他線程正在執行其他任務,並且希望整體響應能力良好。

多線程的整個想法是通過使用更多的計算資源(線程分布在核心之間)來更快地完成工作,從而提高CPU利用率。

如果要降低CPU利用率,請不要使用多線程,將程序粘貼到單線程。 它將運行更長時間,但消耗更少的CPU(當然,有很多優化可以減少CPU占用空間,但它們不是關於多線程)。

如果要監視網絡中的300個節點,那就完全是另一回事了。 你的例子在這里是錯誤的,因為你嘗試了計算密集型任務。 網絡監控不是計算密集型的,它由“請求 - 等待 - 進程響應”循環組成,它們很好地並行化:即使一個CPU可以有效地處理來自一個節點的響應,同時等待來自另一個節點的響應。 更重要的是,因為網絡等待實際上是一個I / O等待,所以這個等待可以很容易地卸載到您的操作系統,因此它不會消耗CPU。

在Richter的“CLR via C#,3rd edition”中有一個關於線程(和I / O等待)的好章節,我強烈建議您解決問題。

我讀過你的處理器可以處理兩種主要的不同類型的活動。 我可能在這些語句中有錯誤的措辭/語法,如果有人可以糾正語法,我將不勝感激。

  1. 計算工作(計算限制):向處理器提供純計算任務,處理器可以在其上工作,無需外部設備或組件的任何輸入。

  2. 基於輸入的工作(I / O界限):當您的處理器正在處理某些事情時,還需要讀取或寫入某些內容,或者它需要等待網絡活動。 例如,從磁盤讀取文件或下載文件。

它們之間的主要區別在於計算應該在沒有等待的情況下使用,以便在盡可能最快的時間內完成任務。 例如:

for(int i = 0; i<= 10000; i++)
{

}

沒有與系統中任何“慢”部分的交互,所以對於這樣的事情,你不介意計算/計算耗盡cpu,因為它可能無論如何都要在微秒的空間中完成。

這對於挖掘比特幣或強制組合等特別重要。

你沒有為這些添加'睡眠',因為它會不必要地減慢你的速度。

但是,如果您的工作負載是基於輸入的,則需要讀取或寫入硬盤驅動器或網絡; 與純數學工作相比,被認為是緩慢的活動,然后添加Thread.Sleep(x)並不是壞事,因為有時你的硬盤驅動器/ Ram速度產生數據的速度不如處理器所希望的那么快。

線程在這兩個不同的主題中特別有趣,對於計算工作,您希望線程在100%不間斷運行一段時間,那么您最好不要超過線程計數中的處理器計數。

例如: Environment.ProcessorCount

事實上,我幾乎建議使用Environment.ProcessorCount -1計數,即Environment.ProcessorCount -1 (在雙核或更高核的情況下)使用100%的所有核心/處理器可能導致線程鎖定,這實際上會阻礙性能。

我對此進行了實驗,發現在雙核系統上,我可以使用單核完成更多的循環/迭代,而不是完全使用兩個核。

如果我使用四核,我發現通過使用3對全部4可以獲得更多。

(別忘了,其中一個處理器必須共享操作系統功能,以及渲染窗體應用程序GUI - 如果有的話)

但是,如果您正在開發使用基於輸入的計算的應用程序,它需要與許多慢速設備或依賴項進行交互,那么超出處理器數量可能並不是一件壞事。

例如:如果每個線程中都有很多thread.sleeps,那么您可以策略性地規划線程休眠,而其他線程可以工作。

我過去使用多線程實驗室監視器完成了這項工作,該監視器旨在監視工作中實驗室機器的狀態; 對於每個實驗室機器,線程都會運行。 但它實際上每10分鍾才開始工作一次。

最初的問題,沒有完全理解多線程的概念。

由於您有單線程並且它們沒有延遲(線程)處理器被占用 100%。

即使您創建了多個任務(比如 100 個),那么所有任務都將並行執行並且處理器利用率將保持 100%

改變這個:

for (int i = 0; i < 10000000; i++) Console.Write("x");

進入這段代碼:

for (int i = 0; i < 10000000; i++) 
    {
       Console.Write("x");
       Thread.Sleep(5);
    }

采用

Thread.Sleep(x); //where x >= 0

要么

Thread.Yield();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM