2012-11-05 34 views
2

我試圖使多線程webrequests,但如果我有超過2試試我得到錯誤C#錯誤

Index was outside the bonds of the array 

在這條線:

string username = ScrapeBox1.Lines[NamesCounter].ToString(); 

下面的代碼:

while (working) 
{ 
    while (usernamescount > NamesCounter) 
    { 
     string username = ScrapeBox1.Lines[NamesCounter].ToString(); 
     string url = "http://www.someforum.com/members/" + username + ".html"; 
     var request = (HttpWebRequest)(WebRequest.Create(url)); 
     var response = request.GetResponse(); 
     request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; rv:16.0) Gecko/20100101 Firefox/16.0"; 

     using (var responseStream = response.GetResponseStream()) 
     { 
      using (var responseStreamReader = new StreamReader(responseStream)) 
      { 

       var serverResponse = responseStreamReader.ReadToEnd(); 
       int startpoint = serverResponse.IndexOf("Contact Info</span>"); 
       try 
       { 
        string strippedResponse = serverResponse.Remove(0, startpoint); 
        ExtractEmails(strippedResponse); 

       } 
       catch { } 


      } 
     } 
     NamesCounter++; 
     textBox1.Text = NamesCounter.ToString(); 
    } 

} 
+1

你的代碼顯然不是線程安全的。你認爲會發生什麼? –

+0

是的,但我不想在整個方法上使用鎖,因爲這會使多線程無意義。如果我只把一個鎖放在NamesCounter上,我仍然會得到相同的錯誤 –

+1

你(可能)不需要在整個方法上保持鎖定,只需要那些將被多個線程訪問的變量... –

回答

2

此代碼不是線程安全的。

你需要執行HttpWebRequest的代碼是原子的,並且在循環集合的上下文之外。

例如

public void MakeHttpWebRequest(string userName) 
{ 
    string url = "http://www.someforum.com/members/" + userName + ".html"; 
    var request = (HttpWebRequest)(WebRequest.Create(url)); 
    var response = request.GetResponse(); 
    request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; rv:16.0) Gecko/20100101 Firefox/16.0"; 

    using (var responseStream = response.GetResponseStream()) 
    { 
     using (var responseStreamReader = new StreamReader(responseStream)) 
     { 

      var serverResponse = responseStreamReader.ReadToEnd(); 
      int startpoint = serverResponse.IndexOf("Contact Info</span>"); 
      try 
      { 
       string strippedResponse = serverResponse.Remove(0, startpoint); 
       ExtractEmails(strippedResponse); 

      } 
      catch { } 


     } 
    } 
} 

假設ScrapeBox.Lines實現IEnumerable,我會建議使用Parallel.ForEach並傳遞ScrapeBox.Lines作爲IEnumerable的一個要迭代。

現在,還有一個額外的問題,即從HttpWebRequest讀取響應的代碼仍然需要將其輸出寫入共享位置。以線程安全的方式完成此任務。一個常見的做法是使用信號量。你需要一個對每個線程實例都可訪問的對象。類級別的私有變量private object sharedMutex = new object();會起作用。然後代碼ExtractEmails(strippedResponse);應改爲 lock(sharedMutex) { ExtractEmails(strippedResponse); }

而不必爲ExtractEmails(<string>)方法的代碼,我不能提供一個線程安全的實現,因此該解決方案的一部分仍可能會引起問題。

+0

我upvoted你的答案,直到我看到你忽略例外。但是,我不會冷靜下來。 –

+1

這只是原始代碼的修改版本,我只是簡單地將線程安全項添加到它中......而不是試圖完全重寫它。另外,如果不知道代碼的真實目的,除了標準日誌並繼續前進之外,很難知道如何處理異常。 – mckeejm