C#解析时同时启动所有线程

时间:2017-01-29 19:18:29

标签: c# xml-parsing multitasking

我目前正在学习C#,过去两天我一直在研究XML解析器。它实际上工作正常我的问题是解析超过10k页所花费的时间。这是我的代码。

    public static void startParse(int id_min, int id_max, int numberofthreads)
    {
        int start;
        int end;
        int part;
        int threadnbrs;

        threadnbrs = numberofthreads;
        List<Thread> workerThreads;
        List<string> results;

        part = (id_max - id_min) / threadnbrs;
        start = id_min;
        end = 0;
        workerThreads = new List<Thread>();
        results = new List<string>();

        for (int i = 0; i < threadnbrs; i++)
        {
            if (i != 0)
                start = end + 1;
            end = start + (part);
            if (i == (threadnbrs - 1))
                end = id_max;

            int _i = i;
            int _start = start;
            int _end = end;

            Thread t = new Thread(() =>
            {

                   Console.WriteLine("i = " + _i);
                   Console.WriteLine("start =" + _start);
                   Console.WriteLine("end =" + _end + "\r\n");
                   string parse = new ParseWH().parse(_start, _end);
                   lock (results)
                   {
                       results.Add(parse);
                   }
            });
            workerThreads.Add(t);
            t.Start();
        }
        foreach (Thread thread in workerThreads)
               thread.Join();

        File.WriteAllText(".\\result.txt", String.Join("", results));
        Console.Beep();
    }

我实际上在做的是在不同的线程中拆分需要解析的一系列元素,以便每个线程处理X元素。

每100个元素需要大约20秒。 但是我花了17分钟来解析10 0000个元素。

我需要的是每个线程同时在这10 000个元素中的100个上工作,所以它可以在20秒内完成。是否有解决方案?

解析代码:

public string parse(int id_min, int id_max)
        {
            XmlDocument xml;
            WebClient user;
            XmlElement element;
            XmlNodeList nodes;
            string result;
            string address;
            int i;

            //Console.WriteLine(id_min);
            //Console.WriteLine(id_max);
            i = id_min;
            result = "";
            xml = new XmlDocument();
            while (i <= id_max)
            {
                user = new WebClient();
                // user.Headers.Add("User-Agent", "Mozilla/5.0 (Linux; U; Android 4.0.3; ko-kr; LG-L160L Build/IML74K) AppleWebkit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30");
                user.Encoding = UTF8Encoding.UTF8;
                address = "http://fr.wowhead.com/item=" + i + "?xml";
                if (address != null)
                    xml.LoadXml(user.DownloadString(new Uri(address)));
                element = xml.DocumentElement;
                nodes = element.SelectNodes("/wowhead");
                if (xml.SelectSingleNode("/wowhead/error") != null)
                {
                    Console.WriteLine("error " + i);
                    i++;
                    continue;
                }
                result += "INSERT INTO item_wh (entry, class, subclass, displayId, ,quality, name, level) VALUES (";
                foreach (XmlNode node in nodes)
                {
                    // entry
                    result += node["item"].Attributes["id"].InnerText;
                    result += ", ";
                    // class
                    result += node["item"]["class"].Attributes["id"].InnerText;
                    result += ", ";
                    // subclass
                    result += node["item"]["subclass"].Attributes["id"].InnerText;
                    result += ", ";
                    // displayId
                    result += node["item"]["icon"].Attributes["displayId"].InnerText;
                    result += ", ";
                    // quality
                    result += node["item"]["quality"].Attributes["id"].InnerText;
                    result += ", \"";
                    // name
                    result += node["item"]["name"].InnerText;
                    result += "\", ";
                    // level
                    result += node["item"]["level"].InnerText;
                    result += ");";
                    // bakcline
                    result += "\r\n";
                }
                i++;
            }
            return (result);
        }

3 个答案:

答案 0 :(得分:0)

CPU绑定工作(例如解析)的最佳解决方案是启动与计算机中核心数量一样多的线程,少于此并且您没有利用所有核心,超过这个并且过多上下文切换可能会启动并阻碍性能。

基本上,threadnbrs应设置为Environment.ProcessorCount

另外,请考虑使用Parallel类而不是自己创建线程:

Parallel.ForEach(thingsToParse, (somethingToParse) =>
        {
            var parsed = Parse(somethingToParse);
            results.Add(parsed);
        });

您必须同意它看起来更干净,更容易维护。 此外,您最好使用ConcurrentBag而不是常规的List +锁,因为ConcurrentBag更适合并发加载,并且可以为您提供更好的性能。

答案 1 :(得分:0)

最后!通过同时启动我的应用程序的多个过程来实现它。

Witch意味着我有10个k元素,我在1000个元素的10个过程中运行。增加进程数量以减少元素数量,它会越来越快! (我目前正在以非常快的Internet速度运行)并拥有三星M.2 960作为存储以及核心I7 Skylake 6核心

答案 2 :(得分:0)

好的,所以我发现&#34; Trying to run multiple HTTP requests in parallel, but being limited by Windows (registry)&#34;它被称为&#34;线程池&#34;我最终决定直接下载XML文件,然后直接解析文档,而不是直接解析网站以获得SQL格式。新的方法工作,我可以在9秒内下载和写入多达10 000 K XML。我试图把它推到150 K(所有网站页面),但现在我得到了一个奇怪的错误,我得到了重复的项目......我将尝试使用正确的方法重写完整的代码,多任务/线程,字典和IEnumerable容器交叉手指在150 k项目上运行而不会丢失正在处理的数据并回发完整代码。