2013-04-03 34 views
-1

我有一個網站,我寫了一個HttpModule來轉換所有鏈接,所以每件事情都很好,直到我要在轉換URL時使用並行性。與任務並行,有些任務工作,有些不是

這是我的測試控制檯應用程序:

class Program 
    { 
     static void Main(string[] args) 
     { 
      new Job().Do(); 
     } 
    } 

    public class Job 
    { 
     public void Do() 
     { 
      string content = @" 
      new link1 href=""www.yahoo1.com"" end 
      new link2 href=""www.yahoo2.com"" end 
      new link3 href=""www.yahoo3.com"" end 
      new link4 href=""www.yahoo4.com"" end 
      new link5 href=""www.yahoo5.com"" end 
      new link6 href=""www.yahoo6.com"" end 
      "; 

      string newcontent = Transformlink(content); 

      Console.WriteLine(content); 
      Console.WriteLine(); 
      Console.WriteLine(newcontent); 
      Console.ReadLine(); 
     } 

     private string Transformlink(string content) 
     { 
      List<UrlIndex> AllUrls = GetUrls(content); 
      List<Task> TaskPool = new List<Task>(); 
      foreach (UrlIndex Item in AllUrls) 
       TaskPool.Add(Task.Factory.StartNew(() => TransformUrl(Item))); 
      Task.WaitAll(TaskPool.ToArray()); 

      return ReplaceUrlWithTransformUrl(content, AllUrls); 
     } 

     private string ReplaceUrlWithTransformUrl(string content, List<UrlIndex> AllUrls) 
     { 
      for (int i = AllUrls.Count - 1; i >= 0; i--) 
      { 
       UrlIndex CurrentItem = AllUrls[i]; 
       content = content.Substring(0, CurrentItem.StartIndex) + CurrentItem.TransformedUrl + content.Substring(CurrentItem.EndIndex); 
      } 
      return content; 
     } 

     private void TransformUrl(UrlIndex urlindex) 
     { 
      urlindex.TransformedUrl = string.Format("Google{0}.com", new Random().Next(100, 999).ToString()); 
     } 

     private List<UrlIndex> GetUrls(string content) 
     { 
      //Get Start And End Index, Get Url Set TransformedUrl = Url 
      List<UrlIndex> AllUrls = new List<UrlIndex>(); 
      int startindex = 0; 
      int endIndex = 0; 
      int previousindex = 0; 
      while (startindex != -1) 
      { 
       startindex = content.IndexOf("href=\"", previousindex); 
       if (startindex == -1) 
        break; 
       startindex += 6; 
       previousindex = startindex; 
       endIndex = content.IndexOf("\"", previousindex); 
       if (endIndex == -1) 
        break; 
       previousindex = endIndex; 
       string url = content.Substring(startindex, endIndex - startindex); 
       AllUrls.Add(new UrlIndex() { StartIndex = startindex, EndIndex = endIndex, Url = url, TransformedUrl = url }); 
      } 

      return AllUrls; 
     } 
    } 


    public class UrlIndex 
    { 
     public int StartIndex { get; set; } 
     public int EndIndex { get; set; } 
     public string Url { get; set; } 
     public string TransformedUrl { get; set; } 
    } 

的結果必然是:

new link1 href=""www.Google859.com"" end 
new link2 href=""www.Google245.com"" end 
new link3 href=""www.Google749.com"" end 
new link4 href=""www.Google345.com"" end 
new link5 href=""www.Google894.com"" end 
new link6 href=""www.Google243.com"" end 

這就是我想要的確切事情。

但是結果是:

new link1 href=""www.yahoo1.com"" end 
new link2 href=""www.yahoo2.com"" end 
new link3 href=""www.yahoo3.com"" end 
new link4 href=""www.yahoo4.com"" end 
new link5 href=""www.yahoo5.com"" end 
new link6 href=""www.Google125.com"" end 

正如你看到的只是最後一個環節轉變。在某些情況下:

new link1 href=""www.yahoo1.com"" end 
new link2 href=""www.yahoo2.com"" end 
new link3 href=""www.Google285.com"" end 
new link4 href=""www.yahoo4.com"" end 
new link5 href=""www.yahoo5.com"" end 
new link6 href=""www.Google125.com"" end 

控制檯項目是在.NET 4

這是我的錯嗎?爲什麼所有任務都不起作用Task.WaitAll(TaskPool.ToArray());行是不夠的?任何建議?

回答

4

看起來像封閉問題。 更改Transformlink方法是這樣的:

private string Transformlink(string content) 
    { 
     List<UrlIndex> AllUrls = GetUrls(content); 
     List<Task> TaskPool = new List<Task>(); 
     foreach (UrlIndex Item in AllUrls) 
     { 
      val localItem = Item; 
      TaskPool.Add(Task.Factory.StartNew(() => TransformUrl(localItem))); 
     } 
     Task.WaitAll(TaskPool.ToArray()); 

     return ReplaceUrlWithTransformUrl(content, AllUrls); 
    } 

編輯/解釋:

這是由Tasks安排的方式致毒。你沒有真正的方法來控制它。在您的控制應用程序中,任務執行的計劃「足夠快」,以在循環迭代之前完成。因爲你在TransformUrl中通過的Item變量仍然是你想到的那個。

但是在您的服務器應用程序循環中,在執行任何Task之前完成。 並注意你通過了一個參考。此參考在每次迭代中都會更改。因此,循環完成後,您的所有任務將對相同的UrlIndex實例執行變換。那就是發生了什麼事。 通過創建本地變量,您可以存儲對您想要使用的實際對象的引用。

因此使用局部變量是正確的方法。它適用於控制檯應用程序,因爲正確的時間條件(我會稱它運氣:))

+1

謝謝,這項工作,但爲什麼?局部變量是什麼? – Saeid

+0

@Saeid查看我的更新 –

+1

在這種情況下最好使用Task.ParallelFor –