IEnumerable доходность в сочетании с .AsParallel () - PullRequest
0 голосов
/ 02 июля 2010

Я написал некоторый код, чтобы попытаться описать мою проблему:

static void Main(string[] args)
{
    IEnumerable<decimal> marks = GetClassMarks();
    IEnumerable<Person> students = GetStudents();

    students.AsParallel().ForAll(p => GenerateClassReport(p, marks));

    Console.ReadKey();
}

GetClassMarks использует в нем доходность из моего странного источника данных.Предположим, что GenerateClassReport в основном выполняет marks.Sum () / marks.Count (), чтобы получить среднее по классу.

Из того, что я понимаю, student.AsParallel (). ForAll - это параллельный foreach.1007 * Меня беспокоит то, что произойдет внутри метода GetClassMarks.

  • Будет ли оно перечисляться один или несколько раз?
  • В каком порядке будет происходить перечисление?
  • Нужно ли делать отметки .ToList (), чтобы удостовериться, что он попал только один раз?

Ответы [ 3 ]

4 голосов
/ 05 июля 2010

Будет ли оно перечисляться один или несколько раз?

Если предположить, что GenerateClassReport() перечисляет marks один раз, то marks будет перечисляться один раз для каждого элемента в students.

В каком порядке будет происходить перечисление?

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

Нужно ли делать .ToList () для отметок, чтобы сделатьВы уверены, что он ударил только один раз?

Если GetClassMarks() является итератором (т. е. он использует конструкцию yield), то его выполнение будет отложено и будет вызываться один раз каждый раз marks перечисляется (т.е. один раз для каждого элемента в students).Если вы используете IEnumerable<decimal> marks = GetClassMarks().ToList() или если GetClassMarks() внутренне возвращает конкретный список или массив, то GetClassMarks() будет выполнено немедленно, а результаты будут сохранены и перечислены в каждом из параллельных потоков без повторного вызова GetClassMarks().

1 голос
/ 02 июля 2010
  1. Если GetClassMarks является итератором - то есть, если он использует yield внутри - тогда это фактически запрос, который будет повторно выполняться всякий раз, когда вы вызываете marks.Sum(), marks.Count() и т. Д .

  2. Почти невозможно предсказать порядок выполнения в параллельном запросе.

  3. Да. Следующее обеспечит выполнение GetClassMarks только один раз. Последующие вызовы marks.Sum(), marks.Count() и т. Д. Будут использовать конкретный список вместо повторного выполнения запроса GetClassMarks.

    List<decimal> marks = GetClassMarks().ToList();
    

Обратите внимание, что пункты 1 и 3 применяются независимо от того, используете вы AsParallel или нет. Запрос GetClassMarks будет выполняться одинаковое количество раз в любом случае (при условии, что остальная часть кода, за исключением параллельных аспектов, одинакова).

0 голосов
/ 02 июля 2010

Будет ли оно перечисляться один или несколько раз?

Всего один раз.

В каком порядке будет происходить перечисление?

Итератор (функция, использующая yield) определяет порядок.

Нужно ли делать .ToList () для меток, чтобы удостовериться, что он попал только один раз?ввод в блоки, которые отправляются рабочим потокам.

...