【问题标题】:Parallelism with Task, some tasks worked, some not与任务并行,一些任务有效,一些没有
【发布时间】:2013-04-08 19:51:51
【问题描述】:

我有一个网站,我编写了一个 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()); 的行不够?有什么建议吗?

【问题讨论】:

    标签: c# .net parallel-processing task-parallel-library


    【解决方案1】:

    看起来像一个关闭问题。 像这样更改您的 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 实例上执行转换。这就是发生的事情。 通过创建局部变量,您可以存储对您想要使用的实际对象的引用。

    所以使用局部变量是正确的方法。由于正确的时间条件,它可以在控制台应用程序中运行(我称之为运气:))

    【讨论】:

    • 在这种情况下,最好使用 Task.ParallelFor
    • @AlexOvechkin 我与 Parallel.For 进行比较,但在这种情况下 Parallel.For 的持续时间超过了当前代码
    • @Saeid, Parallel.For 如果你有很多数据,而不是 10 个链接,效率会更高,所以这取决于你的输入
    • @AlexOvechkin 谢谢 Alex 我发现这个:stackoverflow.com/questions/5009181/… 同意你的评论
    猜你喜欢
    • 1970-01-01
    • 2019-10-24
    • 1970-01-01
    • 2010-12-05
    • 2012-06-28
    • 2016-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多