与任务并行,某些任务有效,有些不可行 [英] Parallelism with Task, some tasks worked, some not

查看:92
本文介绍了与任务并行,某些任务有效,有些不可行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个网站,我写了一个HttpModule来转换所有链接,所以一切正常,直到我要在转换URL中使用并行性.

I have a website and I write a HttpModule to convert all links, So every things fine until I going to use parallelism in convert URLs.

这是我的测试控制台应用程序:

This is My Test Console Application:

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

如您所见,仅最后一个链接已转换.在某些情况下:

As you see just the last link transformed. And in Some cases:

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中

Console project is in .NET 4

这是我的错吗?为什么所有任务都不起作用? Task.WaitAll(TaskPool.ToArray());的行不够吗?有什么建议吗?

Is this my fault? Why all tasks not worked? The line of Task.WaitAll(TaskPool.ToArray()); is not enough? any suggestion?

推荐答案

看起来像是关闭问题. 像这样更改您的Transformlink方法:

Looks like a closure problem. Change your Transformlink method like this:

    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变量仍然是您所想到的那个变量.

This is coused by the way Tasks are scheduled. You have no real way to control that. In your control application task execution is scheduled "fast enough" to finish before you loop iteration. Because of that Item variable that you passed inside TransformUrl is still that one you thought about.

但是在您的服务器应用程序中,循环会在执行任何Task之前完成. 并请注意,您已通过参考.该参考在每次迭代中都会更改.因此,循环完成后,所有任务将在同一UrlIndex实例上执行转换.这就是发生的情况. 通过创建局部变量,您可以存储对要使用的实际对象的引用.

But in your server application loop finishes before any Task is executed. And note that you passed a reference. This reference is changed in each iteration. So after loop finished all your tasks will perform transform on the same UrlIndex instance. And that is what happens. By creating local variable you store reference to the actual object that you wanted to use.

因此,使用局部变量是正确的方法.由于正确的计时条件,它可以在控制台应用程序中工作(我称它为运气:))

So using the local variable is the right way to do this. It works in console app because of right timing conditions (I would call it luck :) )

这篇关于与任务并行,某些任务有效,有些不可行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆