2017-01-17 2 views
1

Учитывая приведенный ниже кодФильтрация большое количество XMLNodes с использованием DataContractSerializer очень медленно

List<CustomConversionData> Filter(XmlNodeList nodeList) 
{ 
    var filteredResults= new List<CustomConversionData>(); 
    //Deserailze the data: 
    foreach (XmlNode item in nodeList) 
    { 
     try 
     { 
     CustomConversionData obj = Deserialize<CustomConversionData>(item.ParentNode.OuterXml); 
     filteredResults.Add(obj); 

     } 
     catch 
     { 
      try 
      {            
       CustomConversionData obj = Deserialize<CustomConversionData>(item.OuterXml); 
       filteredResults.Add(obj); 
      } 
      catch (Exception e) { 
      } 
     } 
    } 
    return filteredResults; 
} 

и метод, который делают десериализации

public T Deserialize<T>(string rawXml) 
{ 
    using (XmlReader reader = XmlReader.Create(new StringReader(rawXml))) 
    { 
     DataContractSerializer formatter = 
      new DataContractSerializer(typeof(T)); 
     return (T)formatter.ReadObject(reader); 
    } 
} 

Когда я запускаю это для nodeList, который состоит из 8000 узлов, он занимает около 6 часов. Я искал способ сократить это время, и в начале я подумал, что, возможно, я могу создать задачу для каждой итерации, но она стала медленнее, чем раньше, и я думаю, что это было из-за накладных расходов на переключение между задачами.

Мне было интересно, какой был бы лучший способ улучшить производительность этого кода, поскольку он, по-видимому, очень насыщен процессором и памятью?

+0

Мне нужно увидеть пару разделов xml с повторяющимся основным тегом. 6 часов - это путь к такому маленькому файлу. – jdweng

ответ

2

В вашем методе Deserialize я бы сделал formatter статическим членом, так как каждый раз он будет одинаковым (и я не уверен, что он кэшируется внутри). Затем используйте .ReadObject(new StringReader(rawXml)), чтобы сохранить добавленную сложность ввода XmlReader.

Тогда это становится сложным. Старайтесь не использовать обработку исключений для управления своей логикой, поэтому сначала сделайте некоторую другую проверку, а не дайте ей бросить ее и поймать.

Наконец, я думаю, что самая большая победа была бы не взять XmlNodeList, но взять Stream и создать XmlReader для сканирования XML и только десериализации, что ему нужно, когда это нужно. Первоначальная стоимость того, чтобы все эти графы объектов быстро складывались.

Edit: Еще одно предложение, изменить подпись IEnumerable<CustomConversionData> и yield return, где вы могли бы сделать .Add(...), таким образом, потребляющий код может течь результатов, сохраняя пиковое использование памяти вниз.

Edit2: выбор ParentNode первый раз поражает меня как нечетное. Если XmlNodeList происходит от звонка .ChildNodes, то вы будете десериализовать одно и то же снова и снова. Если это от SelectNodes("..."), то вы можете быть умнее выбирать правильный узел с XPath для начала и не должны получать родителя. Если вам все еще нужно это сделать, создайте здесь XmlReader, проверьте имя элемента и решите, если вам нужен родитель. Если у вас есть правильный элемент, вы можете передать XmlReader в Derserialize, сохранив другую копию.

+0

Спасибо Стюарту, я на самом деле продолжаю разбивку 'nodeList', в который состоял из 8000 узлов в куски 50 и обрабатывал их одновременно, что сокращало время от 6 часов до 7 минут. Я сделаю ваши предложения, потому что в настоящее время я вижу, что с помощью TPL использование процессора и памяти довольно велико и нуждается в дальнейшем улучшении. –

+0

Привет, Stuart, '.ReadObject' не принимает' StringReader', поэтому я не могу использовать '.ReadObject (новый StringReader (rawXml)) ' –

Смежные вопросы