Оптимизация производительности — Реализация шаблона параллельного построения

#c# #design-patterns

Вопрос:

У меня есть сложный шаблон компоновщика, реализованный в коде, аналогичном последнему в этом URL-адресе. Цель разработчиков состоит в том, чтобы построить SQL-запрос на основе свойств объекта.

Что-то вроде

 PersonQueryBuilder person =
                new PersonQueryBuilder.Builder()
                        .BuildAddressClause(request.PersonInformation.Address)
                        .BuildBankAccountClause(request.PersonInformation.BankAccountInformation)
                        .BuildAClause(request.Something)
                        .BuildBClause(request.Something)
                        .build();

 

Я подумал, что вместо последовательного выполнения этих логик построения было бы более эффективно, если бы я мог запускать их с

 TaskFactory.StartNew(() =>
{
// Create builder here so that the builder pattern stays the same, but the process runs concurrently.
});
 

Есть ли какой-либо способ/пример, который может продемонстрировать подобное поведение?

Комментарии:

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

2. Я предлагаю вам взглянуть на разглагольствования Эрика Липперта о производительности : «не вносите изменений, основанных на производительности, если вы не выявили проблему с производительностью».

3. У вас есть реальная проблема? Потому что StartNew, скорее всего, создаст их?

4. Ну что ж! Для 5 из 13 строителей есть 3 вызова службы. Обычно API 2 сторонних сервисов требует времени (m n). А остальные строители-это простые манипуляции со строками и немного LINQ. В результате строителям требуется время, и мой SLA API становится m n x; x-время работы API службы.

Ответ №1:

Прежде всего, с недавним C#, который вы используете Task.Run(...) вместо TaskFactory.StartNew(...) запуска фоновой задачи, запускающей функцию. Однако это не приведет к параллельному запуску сборщиков, для распараллеливания работы, связанной с процессором (я предполагаю, что сборщики не выполняют никаких операций ввода-вывода с диска/сети), вы используете Parallel класс, который, Parallel.Invoke похоже, подходит для вашего случая.

Однако при использовании параллельного класса вам необходимо убедиться, что разные разработчики не изменяют одно и то же состояние, например, не манипулируют общим StringBuilder представлением SQL-запроса. Если вам нужно изменить одно и то же состояние, вы можете при необходимости ввести блокировки для обеспечения потокобезопасности, однако убедитесь, что распараллеливание действительно оправдано.