简体   繁体   English

将90000 XElement添加到XDocument

[英]Adding 90000 XElement to XDocument

I have a Dictionary<int, MyClass> 我有一个Dictionary<int, MyClass>

It contains 100,000 items 它包含100,000个项目

10,000 items value is populated whilst 90,000 are null. 填充了10,000个项目的值,而90,000个为空。

I have this code: 我有以下代码:

var nullitems = MyInfoCollection.Where(x => x.Value == null).ToList();
nullitems.ForEach(x => LogMissedSequenceError(x.Key + 1));

private void LogMissedSequenceError(long SequenceNumber)
        {
            DateTime recordTime = DateTime.Now;

            var errors = MyXDocument.Descendants("ERRORS").FirstOrDefault();
            if (errors != null)
            {

                errors.Add(
                    new XElement("ERROR",
                        new XElement("DATETIME", DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss:fff")),
                        new XElement("DETAIL", "No information was read for expected sequence number " + SequenceNumber),
                        new XAttribute("TYPE", "MISSED"),
                        new XElement("PAGEID", SequenceNumber)
                        )
                );
            }
        }

This seems to take about 2 minutes to complete. 这似乎需要大约2分钟才能完成。 I can't seem to find where the bottleneck might be or if this timing sounds about right? 我似乎找不到瓶颈所在,或者这个时机听起来正确吗?

Can anyone see anything to why its taking so long? 谁能看到为什么花这么长时间的东西?

If your MyInfoCollection is huge, I wouldn't call ToList() on it just so you can use the ForEach extension method. 如果您的MyInfoCollection很大,我不会在上面调用ToList()以便可以使用ForEach扩展方法。 Calling ToList() is going to create and populate a huge list. 调用ToList()将创建并填充一个巨大的列表。 I'd remove the ToList() call, and make the .ForEach into a for each statement, or write a . 我将删除ToList()调用,并将.ForEach放入for each语句的,或编写一个。 ForEach extension method for IEnumerable<T> . IEnumerable<T> ForEach扩展方法。

Then profile it and see how long it takes. 然后分析它,并查看需要多长时间。 One other thing to do is remove the find and null check of the ERRORS element. 要做的另一件事是删除ERRORS元素的find和null检查。 If it's not there, then don't call the for each statement above. 如果不存在,则不要for each上述for each语句调用。 That way you null check it one time instead of 90,000 times. 这样一来,您可以将其空检查一次而不是90,000次。

Plus as Michael Stum pointed out, I'd define a string to hold the value DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss:fff") , then reference it or pass it in. Plus, you don't even use this call: 另外,正如Michael Stum指出的那样,我将定义一个字符串以保存值DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss:fff") ,然后引用它或将其传递。甚至不要使用此调用:

DateTime recordTime = DateTime.Now;

This is what I would most likely do. 这是我最有可能做的。

private void BuildErrorNodes()
{
    const string nodeFormat = @"<ERROR TYPE=""MISSED""><DATETIME>{0}</DATETIME><DETAIL>No information was read for expected sequence number {1}</DETAIL><PAGEID>{1}</PAGEID></ERROR>";

    var sb = new StringBuilder("<ERRORS>");
    foreach (var item in MyInfoCollection)
    {
        if (item.Value == null) 
        {
            sb.AppendFormat(
                nodeFormat,
                DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss:fff"),
                item.Key + 1
            );
        }
    }

    sb.Append("</ERRORS>");

    var errorsNode = MyXDocument.Descendants("ERRORS").FirstOrDefault();
    errorsNode.ReplaceWith(XElement.Parse(sb.ToString()));
}

How about replacing the method call with a LINQ query? 如何用LINQ查询替换方法调用?

static void Main(string[] args)
{

    var MyInfoCollection = (from key in Enumerable.Range(0, 100000)
                            let value = (MoreRandom() % 10 != 0)
                                                    ? (string)null
                                                    : "H"
                            select new { Value = value, Key = key }
                           ).ToDictionary(k => k.Key, v => v.Value);

    var MyXDocument = new XElement("ROOT",
                                    new XElement("ERRORS")
                                  );
    var sw = Stopwatch.StartNew();
    //===
    var errorTime = DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss:fff");
    var addedIndex = MyInfoCollection.Select((item, index) =>
                                                    new
                                                    {
                                                        Value = item.Value,
                                                        Key = item.Key,
                                                        Index = index
                                                    });
    var errorQuery = from item in addedIndex
                     where string.IsNullOrEmpty(item.Value)
                     let sequenceNumber = item.Key + 1
                     let detail = "No information was read for expected " +
                                  "sequence number " + sequenceNumber
                     select new XElement("ERROR",
                        new XElement("DATETIME", errorTime),
                        new XElement("DETAIL", detail),
                        new XAttribute("TYPE", "MISSED"),
                        new XElement("PAGEID", sequenceNumber)
                        );

    var errors = MyXDocument.Descendants("ERRORS").FirstOrDefault();
    if (errors != null)
        errors.Add(errorQuery);
    //===
    sw.Stop();
    Console.WriteLine(sw.ElapsedMilliseconds); //623
}
static RandomNumberGenerator rand = RandomNumberGenerator.Create();
static int MoreRandom()
{
    var buff = new byte[1];
    rand.GetBytes(buff);
    return buff[0];
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM