2014-10-06 90 views
3

我有機會寫在它連接.NET C#應用程序(主要使用「原始」 HTTP請求,部分Web服務和XML請求,仍然通過HTTP)衆多外部系統和更新一些東西他們。多線程網絡爬蟲線程限制

可以有大量的工作排隊在給定時間和天真的方法來增加吞吐量,增加線程數。其背後的邏輯是:因爲大部分時間我們都在等待網絡回覆,所以我們可以同時等待更多的網絡回覆。 CPU和RAM似乎並沒有超出他們的極限。

仍然創造大約300個線程使一切工作比底線計數慢。

我想知道這是一個操作系統的限制(在Windows Server 2012 R2),在.NET(4.5)限制或其他什麼東西?我如何診斷瓶頸在哪裏? (正如我所說的CPU和RAM似乎並不成爲問題)

我知道外部系統可能會過載,並降低整體性能,但是讓我們假設這是可以忽略不計。

+1

'ServicePointManager.DefaultConnectionLimit' ** **可能成爲問題。 – AgentFire 2014-10-06 08:14:55

+0

準確的Windows版本?他們的最大數量和他們的管理是非常不同的。 – 2014-10-06 08:16:21

+0

@AgentFire這似乎是我遇到的問題的直接原因實際上是這個限制。謝謝。 – user1713059 2014-10-09 12:51:33

回答

3

最可能的問題是:

  1. 作爲AgentFire在註釋中指出的,ServicePointManager.DefaultConnectionLimit屬性將限制你可以有一個域的併發連接數。默認值是2.如果您試圖在多個請求中從單個服務器獲取大量數據,那麼您將受到限制。如果需要,您可以增加此值。但請注意,服務器可能會將您的多個連接看作是嘗試的拒絕服務攻擊,並阻止或阻止您。
  2. 看來,東西在.NET HTTP堆棧是單線程。我懷疑它是在DNS解析中。我發現使用多線程可以很容易地維持每秒15到20個請求的吞吐量。這當然取決於你正在下載的文檔的大小和你正在與之通信的服務器的響應能力,但是我運行爬蟲的經驗是,天真的方法(每個線程使用HttpWebRequest一個請求),我最終平均每秒15到20個請求。

在#2的情況下,我懷疑DNS,因爲我跑了單獨的測試中,我做了我正在同域DNS解析,而我的平均值爲每個請求的50至60毫秒。大多數回來真的很快,但有些花了幾秒鐘。另外,當我在本地網絡上放置一個大的DNS緩存時,我的吞吐量顯着增加。

CPU和內存都不會成爲你的限制因素。除了DNS解析之外,您還必須考慮連接速度。如果您有10個併發連接,其中每個都以1 Mb/sec的速率從服務器下載,則您將使10 Mb/s的Internet連接飽和。你應該看看你使用的網絡帶寬。

這些是最大的瓶頸,在我的經驗。你應該調查每一個,看看是否有一個或多個是你感覺糟糕的表現的原因。

+0

實際上,服務器上的默認連接限制爲10(請參閱您提供的註釋)。對我們的需求來說仍然太低。謝謝你的其他評論,他們也很有幫助。 – user1713059 2014-10-09 13:11:57

+0

我選擇這個作爲正確的答案,因爲第一點是我的情況下的實際問題。 – user1713059 2014-10-09 13:23:43

+0

@ user1713059爲什麼你沒有選擇接受的原始答案呢? – AgentFire 2014-10-09 15:47:55

5

創建一個線程需要一些 CPU和RAM,300個線程創建每個線程至少分配1 MB加棧分配以及其他一些東西。

你應該使用線程池爲。池中的線程已經創建好了,正在等待爲您服務。

如果長時間等待網絡響應,可以使用不需要多線程的algorythm。

+0

你寫什麼是真實的,我同意,但它似乎像'ServicePointManager.DefaultConnectionLimit'仍然會限制使用的TCP端口的數量,延緩我們的網絡操作。 – user1713059 2014-10-09 12:53:53

+0

@ user1713059然後在我的評論中對您的問題提出建議,並增加限制。 – AgentFire 2014-10-09 15:45:33

0

您正在從錯誤的角度看待問題,雖然在可以生成並行任務的線程數量的窗口中存在實際的限制,但是這通常很高,但是正如您關於增加線程數看出,性能可能會開始上升,但隨後它必然回落,是由於以下原因:

  • ,線程是一個昂貴的資源,如和創建時
  • 更多線程的數量,處理器內核之間會有更多的上下文切換來服務它們,假設它們處於默認優先級和CPU親和性,浪費更多時間切換上下文並處理所有正在排隊的請求

更好的方法是使用Threadpool,它也被並行API使用,這是爲了優化CPU核心使用並提供最高性能,這裏並行線程的數量將大致等於核心/ CPU可用性,並且在處理完一個請求之後,他們將使下一個請求出隊,因此所有CPU內核都被用於其最佳級別並處理所有請求同時給予最大的槓桿作用。

你會並行API將內部處理所有的複雜性,但如果你不想做這種方式則廣泛適用的規則是目前理想的方法:

number of threads = number of cpu cores * 2 

我已閱讀它在一個權威指南中,目前無法獲得鏈接,您可以嘗試1.5,2,2.5,3之間的選項。這肯定會提高性能,但如何確保每個處理器都是唯一/免費處理器,這仍然是一個挑戰,這是Parallel API負責精確確保負載平衡以實現最佳性能優化的神奇功能。

要進一步添加上述建議,您可以使用異步等待(.net 4.5)代碼標記和任務異步地分離請求,並保持界面響應,但是異步並不總是意味着快,它可能會更慢同樣,因此速度可以達到TPL

+0

線程池的評論是真實的,我同意。但讓我們假設廣泛的上下文切換是實際的問題。它會不會使用大多數(如果不是全部)CPU? – user1713059 2014-10-09 13:15:31

+0

爲什麼我應該限制大部分時間空閒的線程數量(等待服務器回覆)?我想象你說的對於CPU密集型操作來說是正確的。 – user1713059 2014-10-09 13:18:02

+0

第一部分,如果上下文切換是一個問題,那麼它當然並不意味着使用所有CPU優化,當電流執行的線程停止正好與另一個線程被要求繼續前進在給定的處理器/核心,他們在事實上排隊在給定的處理器上。由於調度不在您的手中,並且您沒有使用任何內部優化的API(如並行),所以它肯定會導致更多的排隊和更少的工作,這是由於處理器資源的線程之間的爭用以及時間片的上下文切換 – 2014-10-09 13:28:56

2

當你有足夠的內存時,300個線程根本就不是問題。大多數人本能地嘲笑這樣的建築。同樣的人從未測試過它自己。它工作得很好。操作系統引起的性能問題開始在Win7系統的10000+範圍內出現。操作系統變得生澀使用。

我還是比較喜歡異步IO,因爲你的線程數很高。 但是,同步IO很可能不是您的問題。

我該如何診斷哪裏是瓶頸?

檢查所有可能的瓶頸。 CPU和RAM都不是一個。檢查網絡利用率。你在使用磁盤嗎?你確定你的外部服務沒有完成嗎?它們可能具有併發限制。

我假設你已經提出了.NET連接限制?!找出有多少個請求正在同時進行。我會這樣做:

  1. 暫停調試器,並確保許多線程當前在.NET Web堆棧中。
  2. 查看打開的TCP連接數(Process Explorer或TcpView.exe)
  3. 使用Fiddler並查看同時有多少請求似乎處於活動狀態。
+0

我同意,我的問題的原因不是同步IO,而是'ServicePointManager'中的默認連接限制。謝謝您的意見。 – user1713059 2014-10-09 12:57:10