Выполнение простого запроса LINQ параллельно

Я все еще очень новичок в LINQ и PLINQ. Обычно я просто использую циклы и List.BinarySearch во многих случаях, но я пытаюсь выйти из этого мышления, где могу.

public class Staff
{
  // ...
  public bool Matches(string searchString)
  {
    // ...
  }
}

Использование "нормального" LINQ - извините, я не знаком с терминологией - я могу сделать следующее:

var matchedStaff = from s
                     in allStaff
                  where s.Matches(searchString)
                 select s;

Но я хотел бы сделать это параллельно:

var matchedStaff = allStaff.AsParallel().Select(s => s.Matches(searchString));

Когда я проверяю тип matchedStaff, это список bool s, который не является тем, что я хочу.

Прежде всего, что я делаю неправильно здесь, а во-вторых, как мне вернуть List<Staff> из этого запроса?

public List<Staff> Search(string searchString)
{
  return allStaff.AsParallel().Select(/* something */).AsEnumerable();
}

возвращает IEnumerable<type>, а не List<type>.

Ответ 1

Для вашего первого вопроса вы должны просто заменить Select на Where:

var matchedStaff = allStaff.AsParallel().Where(s => s.Matches(searchString));

Select является оператором проектирования, а не фильтрующим, поэтому вы получаете IEnumerable<bool>, соответствующий проекции всех ваших объектов Staff из входной последовательности в bools, возвращаемые вашим Matches вызов метода.

Я понимаю, что для вас не может быть интуитивно понятным, чтобы вы не использовали Select вообще, поскольку кажется, что вы более знакомы с "синтаксисом запроса", где ключевое слово select является обязательным, что не соответствует синтаксису лямбда ( или "свободный синтаксис"... независимо от наименования), но что это такое;)

Операторы прогнозов, такие как Select, принимают в качестве входных данных элемент из последовательности и преобразуют/проецируют этот элемент каким-то образом на другой тип элемента (здесь проецируется на тип bool). В то время как операторы фильтрации , такие как Where, принимают в качестве входных данных элемент из последовательности и либо выводят элемент как таковой в выходной последовательности, либо вообще не выводят элемент на основе предиката.

Что касается вашего второго вопроса, AsEnumerable возвращает IEnumerable, как указывает его имя;) Если вы хотите получить List<Staff>, вам лучше позвонить ToList() (как указано в названии;)):

return allStaff.AsParallel().Select(/* something */).ToList();

Надеюсь, что это поможет.

Ответ 2

Нет необходимости отказываться от обычного синтаксиса LINQ для достижения parallelism. Вы можете переписать исходный запрос:

var matchedStaff = from s in allStaff
    where s.Matches(searchString)
    select s;

Параллельный LINQ ( "PLINQ" ):

var matchedStaff = from s in allStaff.AsParallel()
    where s.Matches(searchString)
    select s;

Чтобы понять, откуда приходит bool, когда вы пишете следующее:

var matchedStaff = allStaff.AsParallel().Select(s => s.Matches(searchString));

Это эквивалентно следующему синтаксису запроса:

var matchedStaff = from s in allStaff.AsParallel() select s.Matches(searchString);

Как указано darkey, если вы хотите использовать синтаксис С# вместо синтаксиса запроса, вы должны использовать Where():

var matchedStaff = allStaff.AsParallel().Where(s => s.Matches(searchString));