Добавление 90000 XElement в XDocument - PullRequest
2 голосов
/ 15 марта 2010

у меня есть Dictionary<int, MyClass>

Содержит 100 000 наименований

10000 элементов значения заполняется, а 90,000 равны нулю.

У меня есть этот код:

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)
                        )
                );
            }
        }

Похоже, это займет около 2 минут. Кажется, я не могу найти, где может быть узкое место или это звучит правильно?

Кто-нибудь может понять, почему это так долго?

Ответы [ 3 ]

3 голосов
/ 15 марта 2010

Если ваш MyInfoCollection огромен, я бы не стал называть его ToList(), чтобы вы могли использовать метод расширения ForEach. Вызов ToList() собирается создать и заполнить огромный список. Я бы удалил вызов ToList() и превратил бы .ForEach в оператор for each, или написал бы метод расширения. ForEach для IEnumerable<T>.

Тогда профилируйте его и посмотрите, сколько времени это займет. Еще одна вещь, которую нужно сделать, это удалить проверку find и null элемента ERRORS. Если его там нет, не вызывайте оператор for each выше. Таким образом, вы проверяете его один раз вместо 90000 раз.

Кроме того, как указал Майкл Стум, я бы определил строку, содержащую значение DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss:fff"), затем сослался бы на нее или передал ее. Плюс, вы даже не используете этот вызов:

DateTime recordTime = DateTime.Now;
2 голосов
/ 15 марта 2010

Это то, что я бы, скорее всего, сделал.

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()));
}
1 голос
/ 15 марта 2010

Как насчет замены вызова метода запросом 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];
}
...