Параллельное программирование C#, изменяющее xDocument

Я никогда раньше не пробовал параллельное программирование на С#. Итак, прежде чем я вскочил, я хотел бы получить быстрый ответ, чтобы узнать, стоит ли углубляться в это или нет. У меня есть приложения веб-служб С# WCF с .NET 4.0. (возможен апгрейд до 4.5, если работает параллельное программирование)

Все службы являются службами REST. В частности, есть одна услуга, которая иногда занимает очень много времени. Служба обрабатывает и модифицирует XML-документ. служба принимает строку xml в качестве входных данных и возвращает измененный файл xml.

Служба обрабатывает xml в разных местах и ​​в разных элементах. Итак, я создал классы, наследуемые от интерфейса с именем IDocumentProcessor, и у меня есть список этих

Кратко код выглядит так

interface IDocumentProcessor {
     void Process(XDocument doc);
}

public class DateProcessor : IDocumentProcessor
{
   public void Process(XDocument doc) {....};
}

public class CountryProcessor : IDocumentProcessor
{
   public void Process(XDocument doc) {....};
}


public class AddressProcessor : IDocumentProcessor
{
   public void Process(XDocument doc) {....};
}


public class AuthorProcessor : IDocumentProcessor
{
   public void Process(XDocument doc) {....};
}

....

Public class DocumentProcessorService
{
    public class ProcessDocument(string xmlFileAsString) 
    {
        var processorList = new List<IDocumentProcessor>{
            new DateProcessor();
            new CountryProcessor();
            new AddressProcessor();
            new AuthorProcessor();
        }

        var xDocument = XDocument.Parse(xmlFileAsString);
        processorList.forEach(x => x.Process(xDocument));
    }
}

поэтому мой быстрый вопрос, и прежде чем я углублюсь в создание этой параллели: могут ли параллельные вычисления изменять один и тот же объект xDocument (в разных местах)

и можно ли перевести этот код для параллельных вычислений с .net 4.0?


person Ghassan Karwchan    schedule 25.09.2015    source источник
comment
Итак, вы пытаетесь ускорить время, необходимое для завершения ProcessDocument. Сколько раз вы вызываете этот метод (для разных файлов) в секунду или минуту? Может быть, вместо того, чтобы заставить этот метод работать быстрее, вы можете запускать его несколько экземпляров в разных документах?   -  person Yacoub Massad    schedule 25.09.2015
comment
Мы уже запускаем много экземпляров службы. У нас есть балансировщик нагрузки. Но для некоторых файлов (размером в несколько гигабайт) обслуживание занимает иногда 5 минут   -  person Ghassan Karwchan    schedule 25.09.2015
comment
Если у вас, скажем, 8 ядер ЦП, и вы запускаете 8 экземпляров в 8 разных потоках, то параллельное выполнение цикла внутри метода не даст вам никакой производительности.   -  person Yacoub Massad    schedule 25.09.2015
comment
В самом деле? Зачем? если я обрабатываю даты параллельно с обработкой адресов, не должно ли это быть быстрее?   -  person Ghassan Karwchan    schedule 25.09.2015
comment
Вы уже запускаете несколько экземпляров класса DocumentProcessorService в разных потоках, верно? У вас есть ограниченное количество ядер процессора. Если вы используете 16 потоков, а ваш процессор имеет только 8 ядер, то каждые 2 потока будут совместно использовать одно ядро. Это означает, что пока один из этих двух потоков работает, другой должен ждать.   -  person Yacoub Massad    schedule 25.09.2015
comment
большое спасибо за вашу информацию. Я не очень хорошо разбираюсь в том, как IIS/.NET WCF распределяется между процессорами. То, что я знаю, что наша прод-машина, каждая из которых имеет 6 процессоров, разделенных на 3 виртуальных сокета, при этом каждый сокет имеет 2 ядра. Как я могу узнать, сколько запущено экземпляров служб wcf и могу ли я это контролировать? Есть книги или статьи об этом?   -  person Ghassan Karwchan    schedule 25.09.2015
comment
если у вас есть файлы размером всего в несколько гигабайт, вам следует пересмотреть свой дизайн   -  person George Polevoy    schedule 25.09.2015


Ответы (2)


Из документации XElement:

Потокобезопасность Любые общедоступные статические (общие в Visual Basic) члены этого типа являются потокобезопасными. Любые члены экземпляра не гарантируют потокобезопасность.

В основном это означает, что вы не можете изменять XDocument параллельно.

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

Таким образом, он не масштабируется.

Может не хватить типов операций для форка для каждого ядра ЦП, и один тип может завершиться намного быстрее, чем другой. Также высока конкуренция.

Если ваш документ содержит набор высокоуровневых элементов схожей схемы, вы можете параллельно обрабатывать их копии, а затем заменять старые на новые.

Операция повторной сборки должна выполняться в одном потоке и не должна быть слишком дорогой, если вы выберете правильный уровень детализации.

В основном вам нужен конструктор копирования для каждого XElement, который должен быть обработан.

    var newElements = collectionElement.Elements().Select(el=>
    Process(new XElement(el))).AsParallel();

  var newCollection = new XElement("items", newElements);
person George Polevoy    schedule 25.09.2015
comment
это выглядит великолепно. Я очень рад попробовать это. Спасибо большое сообщу о результатах. - person Ghassan Karwchan; 25.09.2015

Может несколько потоков одновременно изменять экземпляр XDocument — да, ничто явно не останавливает поток для внесения изменений (в отличие, например, от операций пользовательского интерфейса в WinForms/WPF).

Но поскольку тип XDocument не является потокобезопасным классом, результаты совершенно непредсказуемы.

Правильная реализация должна предотвращать параллельный доступ к одному и тому же XDocument (т.е. использование lock вокруг операций доступа), пока доступ сериализуется, вы можете изменить его из любого потока.

person Alexei Levenkov    schedule 25.09.2015