Parallel.ForEach и проблема с исходным элементом IGrouping - PullRequest
0 голосов
/ 15 октября 2011

Я пытаюсь распараллелить запрос с помощью оператора groupby. Запрос похож на

    var colletionByWeek = (
                             from item in objectCollection
                             group item by item.WeekStartDate into weekGroups
                             select weekGroups
                          ).ToList();

Если я использую Parallel.ForEach с разделяемой переменной, как показано ниже, она работает нормально. Но я не хочу использовать общие переменные в параллельном запросе.

var pSummary=new List<object>();
Parallel.ForEach(colletionByWeek, week =>
                                {
                                    pSummary.Add(new object()
                                    {
                                        p1 = week.First().someprop,
                                        p2= week.key,
                                        .....
                                    });
                                }
                 );  

Итак, я изменил приведенный выше параллельный оператор, чтобы использовать локальные переменные. Но компилятор жалуется на тип источника <IEnumerable<IGrouping<DateTime, object>>, который не может быть преобразован в System.Collections.Concurrent.OrderablePartitioner<IEnumerable<IGrouping<DateTime, object>>.

Я указываю неверный тип источника? или этот тип IGouping обрабатывается по-другому? Любая помощь будет оценена. Спасибо!

 Parallel.ForEach<IEnumerable<IGrouping<DateTime, object>>, IEnumerable<object>>
                        (spotColletionByWeek,
                         () => new List<object>(),
                         (week, loop, summary) =>
                         {
                             summary.Add(new object()
                             {
                                            p1 = week.First().someprop,
                                            p2= week.key,
                                            .....
                           });
                             return new List<object>();
                         },
                         (finalResult) => pSummary.AddRange(finalResult)
                        );

Ответы [ 2 ]

2 голосов
/ 15 октября 2011

Параметр типа TSource является типом элемента, а не типом коллекции.А второй параметр типа представляет тип локального хранилища, поэтому он должен быть List<T>, если вы хотите Add() к нему.Это должно работать:

Parallel.ForEach<IGrouping<DateTime, object>, List<object>>

Предполагается, что у вас на самом деле нет object s, а есть какой-то определенный тип.

Хотя явные параметры типа здесь даже не нужны.Компилятор должен иметь возможность их выводить.

Но в коде есть и другие проблемы:

  • вы не должны возвращать новый List из основного делегата,но summary

  • делегат, который обрабатывает finalResult, может выполняться одновременно в нескольких потоках, поэтому следует использовать блокировки или одновременную коллекцию там.

1 голос
/ 15 октября 2011

Я собираюсь пропустить этап «Вы уверены, что вам даже нужно оптимизировать этот этап» и предположить, что у вас есть проблема с производительностью, которую вы надеетесь решить путем распараллеливания.

Прежде всего, вы не оказываете никакой помощи, пытаясь использовать Parallel.Foreach<> для этой задачи. Я уверен, что вы получите читаемый и более оптимальный результат, используя PLINQ:

var random = new Random();
var weeks = new List<Week>();
for (int i=0; i<1000000; i++)
{
    weeks.Add(
      new Week {
          WeekStartDate = DateTime.Now.Date.AddDays(7 * random.Next(0, 100))
      });
}

var parallelCollectionByWeek =
    (from item in weeks.AsParallel()
     group item by item.WeekStartDate into weekGroups
     select new
     {
       p1 = weekGroups.First().WeekStartDate,
       p2 = weekGroups.Key,
     }).ToList();

Стоит отметить, что при распараллеливании оператора GroupBy есть некоторые накладные расходы, поэтому в лучшем случае выгода будет незначительной. (Некоторые грубые тесты указывают на ускорение на 10-20%)

Кроме того, причина, по которой вы получаете ошибку компиляции, заключается в том, что первый параметр Type должен быть IGrouping<DateTime, object>, а не IE<IG<..,..>>.

...