【问题标题】:C# Starting all thread in the same time while parsingC#在解析时同时启动所有线程
【发布时间】:2017-01-29 19:18:29
【问题描述】:

我目前正在学习 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);
        }

【问题讨论】:

  • 所以解析 100 个元素需要 20 秒...您如何期望获得 1000 倍的吞吐量,在相同的时间内解析 1000 倍的元素?线程不仅神奇地为您提供免费的计算能力或网络带宽(我们不知道这 100 个元素需要花费什么时间)。
  • @JonSkeet - 但是添加线程将允许它们访问多个 CPU 内核,而线性执行最多只能使用一个内核。在多核机器上,线程将把更多的核心加入到程序中。完全同意这里的问题是解析 100 个项目所花费的时间非常多。
  • @PhillipH 在一台典型的现代计算机上,比如说,8 核,你最多可以得到 7-8 倍的加速,而不是 1000 倍。附带说明一下,其他事情很快就会成为瓶颈(如网络或磁盘 IO)。您最好对代码进行分析以找出为什么您的解析需要这么长时间并改正它。
  • @PhillipH:不,它没有提供“无魔法的计算能力”——它可以让你更好地利用现有的能力。 7 或 8 的因数是合理的 - 1000 的因数是完全不合理的,基本上是对魔术的期望。
  • @PhilippeMakzoume 首先,该网站是否可以像这样受到重创?虽然可以在 20 秒内向网络服务器发送 10,000 个请求,但大多数网站管理员不会因此而喜欢你。如果它是您的服务器,我强烈建议您添加一个端点,该端点在单个请求中响应所有项目。如果您不能使用这样的页面并且服务器可以接受请求,那么请改用异步 HTTP。

标签: c# xml-parsing multitasking


【解决方案1】:

CPU 密集型工作(例如解析)的最佳解决方案是启动与机器中的内核数量一样多的线程,少于该数量,并且您没有利用所有内核,多于该数量且过多上下文切换可能会启动并影响性能。

所以本质上,threadnbrs 应该设置为 Environment.ProcessorCount

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

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

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

【讨论】:

    【解决方案2】:

    终于!通过同时启动我的应用程序的多个进程使其工作。

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 2021-11-21
        • 1970-01-01
        • 2023-03-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-08
        • 2021-02-04
        • 2017-01-02
        相关资源
        最近更新 更多