2013-04-03 37 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 –