首页 > 解决方案 > 23 kB XML 文件的解析速度超过半秒

问题描述

我正在尝试基于 xmlreader 构建对象:

        List<Element> units = new List<Element>();

        string path = "D:\\Item\\Unit.xml";

        XElement xelement = XElement.Load(path);
        IEnumerable<XElement> elements = xelement.Elements();

        foreach (var c in elements)
        {
            Element stb = new Element();
            stb.Name = c.Element("Name").Value;
            stb.Picture = c.Element("Picture").Value;
            //and next 30 options included try / catch for int.Parse
         }

XML:

<?xml version="1.0" encoding="UTF-8"?>
<rows>
<row id="1">
    <Name>Freighter</Name>
    <Picture>Item\Freighter.gif</Picture>
    ... and 30 next rows with data for each "unit"
</row>
    ... and 30 next units...
<rows>

正如我所说,XML 是 23kB 文件,每个单元有 30 行,文件中总共有 30 个单元。不知道为什么这段代码这么慢:花了 670 毫秒(i3 处理器)。最慢的部分是对象填充,但不知道如何改进它。

完整的代码看起来完全一样:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Diagnostics;

namespace element_reader
{
    class Program
    {
        static void Main(string[] args)
        {
            CustomStopwatch sw = new CustomStopwatch();
            sw.Start();

            List<Element> ships = new List<Element>();

            string path = "D:\\Ship_test.xml";

            XElement xelement = XElement.Load(path);
            IEnumerable<XElement> elements = xelement.Elements();

            sw.Stop();
            Console.WriteLine("Stopwatch elapsed: {0}, StartAt: {1}, EndAt: {2}", sw.ElapsedMilliseconds, sw.StartAt.Value, sw.EndAt.Value);
            sw.Start();

            foreach (var c in elements)
            {
                Element stb = new Element();
                stb.Name = c.Element("Name").Value;
                stb.Picture = c.Element("Picture").Value;

                try
                {
                    stb.Prt = int.Parse(c.Element("PRT").Value);
                }
                catch
                { stb.Prt = 0; }

                try
                {
                    stb.Lrt = int.Parse(c.Element("LRT").Value);
                }
                catch
                { stb.Lrt = 0; }

                stb.Special = c.Element("Special").Value;

                try
                {
                    stb.Wep = int.Parse(c.Element("Wep").Value);
                }
                catch
                { stb.Wep = 0; }

                try
                {
                    stb.Con = int.Parse(c.Element("Con").Value);
                }
                catch
                { stb.Con = 0; }

                try
                {
                    stb.Ene = int.Parse(c.Element("Ene").Value);
                }
                catch
                { stb.Ene = 0; }

                try
                {
                    stb.Ele = int.Parse(c.Element("Ele").Value);
                }
                catch
                { stb.Ele = 0; }

                try
                {
                    stb.Prp = int.Parse(c.Element("Prp").Value);
                }
                catch
                { stb.Prp = 0; }

                try
                {
                    stb.Bio = int.Parse(c.Element("Bio").Value);
                }
                catch
                { stb.Bio = 0; }


                try
                {
                    stb.Mass = int.Parse(c.Element("Mass").Value);
                }
                catch
                { stb.Mass = 0; }


                try
                {
                    stb.Iro = int.Parse(c.Element("Iro").Value);
                }
                catch
                { stb.Iro = 0; }

                try
                {
                    stb.Bor = int.Parse(c.Element("Bor").Value);
                }
                catch
                { stb.Bor = 0; }

                try
                {
                    stb.Ger = int.Parse(c.Element("Ger").Value);
                }
                catch
                { stb.Ger = 0; }

                try
                {
                    stb.Res = int.Parse(c.Element("Res").Value);
                }
                catch
                { stb.Res = 0; }


                ships.Add(stb);
            }

            sw.Stop();
            Console.WriteLine("Stopwatch elapsed: {0}, StartAt: {1}, EndAt: {2}", sw.ElapsedMilliseconds, sw.StartAt.Value, sw.EndAt.Value);
            Console.Read();
        }
    }

    public class Element
    {
        public string Name;
        public string Picture;

        public int Prt;
        public int Lrt;

        public string Special;

        public int Con;
        public int Wep;
        public int Ene;
        public int Ele;
        public int Prp;
        public int Bio;

        public int Mass;

        public int Iro;
        public int Bor;
        public int Ger;
        public int Res;
    }

    public class CustomStopwatch : Stopwatch
    {

        public DateTime? StartAt { get; private set; }
        public DateTime? EndAt { get; private set; }


        public void Start()
        {
            StartAt = DateTime.Now;

            base.Start();
        }

        public void Stop()
        {
            EndAt = DateTime.Now;

            base.Stop();
        }
    }
}

当 XML 的部分看起来完全一样时:

<?xml version="1.0" encoding="UTF-8"?>
<rows>
<row id="1">
    <Name>Small Freighter</Name>
    <Picture>Item\Ship\Ship01_1.gif</Picture>
    <Description></Description>
    <PRT></PRT>
    <LRT></LRT>
    <Special></Special>

    <Ene>0</Ene>
    <Wep>0</Wep>
    <Prp>0</Prp>
    <Con>0</Con>
    <Ele>0</Ele>
    <Bio>0</Bio>

    <Slot1>-150, 0, Engine, 1, 1, 1</Slot1>
    <Slot2>-50, 0, Cargo, 70, 1, 1</Slot2>
    <Slot3>50, 0, DEF, 1, 1, 1</Slot3>
    <Slot4>150, 0, SEM, 1, 1, 1</Slot4>

    <Mass>25</Mass>

    <Res>20</Res>
    <Iro>12</Iro>
    <Res>0</Res>
    <Ger>17</Ger>

    <Fuel>130</Fuel>
    <Cargo>70</Cargo>
    <HPD_arm>25</HPD_arm>
    <Initiative>0</Initiative>
</row>
</rows>

1kB 文件的结果是 70 毫秒!!!如果我要加载 20 个文件,每个文件有 20-30 行,则此方法完全没用。请注意,我不使用文件中的所有数据。

标签: c#xml

解决方案


你没有提供完整xml的文件内容,所以我只能建议你一件事。
使用int.TryParse而不是int.Parse. 我敢打赌,您的代码会引发数百个 CPU 非常昂贵的异常。


推荐阅读