Язык

Производительность цепочки запросов (LINQ to XML)

Одним из наиболее важных преимуществ LINQ (и LINQ to XML) является то, что цепочки запросов могут выполняться так же эффективно, как и один более большой и сложный запрос.

Цепной запрос — это запрос, который использует другой запрос в качестве источника. Например, в следующем простом коде query2 имеет query1 как источник.

XElement root = new XElement("Root",
    new XElement("Child", 1),
    new XElement("Child", 2),
    new XElement("Child", 3),
    new XElement("Child", 4)
);

var query1 = from x in root.Elements("Child")
             where (int)x >= 3
             select x;

var query2 = from e in query1
             where (int)e % 2 == 0
             select e;

foreach (var i in query2)
    Console.WriteLine("{0}", (int)i);
Dim root As New XElement("Root", New XElement("Child", 1), New XElement("Child", 2), New XElement("Child", 3), New XElement("Child", 4))

Dim query1 = From x In root.Elements("Child") Where CInt(x) >= 3x

Dim query2 = From e In query1 Where CInt(e) Mod 2 = 0e

For Each i As var In query2
    Console.WriteLine("{0}", CInt(i))
Next

В примере получается следующий вывод.

4

Этот цепной запрос обеспечивает тот же профиль производительности, что и итерация по связанному списку.

  • Elements Ось имеет по сути ту же производительность, что итерацию по связанному списку. Elements реализуется как итератор с отложенным выполнением. Это подразумевает, что в дополнение к итерации по связанному списку выполняются такие действия, как создание объекта итератора и отслеживание состояния выполнения. Эта работа может быть разделена на две категории: работа, выполняемая во время настройки итератора, и работа, выполняемая во время каждой итерации. Работа по настройке является небольшим, фиксированным объемом работы, и работа, выполняемая во время каждой итерации, пропорциональна количеству элементов в исходной коллекции.
  • В query1 предложении where (Where в Visual Basic), запрос вызывает метод Where. Этот метод также реализуется как итератор. Работа по настройке состоит из создания экземпляра делегата, который будет ссылаться на лямбда-выражение, далее идет обычная настройка для итератора. При каждой итерации делегат вызывается для выполнения предиката. Работа по настройке и работа, выполненная во время каждой итерации, аналогична работе, выполняемой при итерации по оси.
  • В предложении query1 оператор select заставляет запрос вызывать метод Select. Этот метод имеет тот же профиль производительности, что и метод Where.
  • В query2 как условие where (Where в Visual Basic), так и условие select имеют одинаковый профиль производительности, как и в query1.

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

Дополнительные сведения об итераторах см. в разделе "Доходность".

Более подробное руководство по цепочке запросов см. в руководстве по цепочке запросов (C#).