Linq - это набор технологий, которые работают вместе для решения аналогичного семейства проблем - во всех из них у вас есть источник данных (XML-файл или файлы, содержимое базы данных, коллекция объектов в памяти), и вы хотите извлечь некоторые или все эти данные и действуют на них каким-либо образом. Linq работает над общим набором проблем, таких как:
var brithdays = from user in users where
user.dob.Date == DateTime.Today && user.ReceiveMails
select new{user.Firstname, user.Lastname, user.Email};
foreach(bdUser in birthdays)
SendBirthdayMail(bdUser.Firstname, bdUser.Lastname, bdUser.Email);
И эквивалент (явное использование связанных с Linq классов и методов с традиционным синтаксисом C #):
var birthdays = users
.Where(user => user.dob.Date == DateTime.Today)
.Select(user => new{user.Firstname, user.Lastname, user.Email});
foreach(bdUser in birthdays)
SendBirthdayMail(bdUser.Firstname, bdUser.Lastname, bdUser.Email);
Оба примера кода, который может работать независимо от того, будет ли он преобразован в вызовы базы данных, синтаксический анализ документов XML или поиск по массиву объектов.
Единственная разница в том, что это за объект users
. Если бы это был список, массив или другая перечисляемая коллекция, это было бы linq-to-objects, если бы это было System.Data.Linq.Table
, это было бы linq to sql. Первое приведет к операциям в памяти, последнее к SQL-запросу, который затем будет десериализован для объектов в памяти как можно позже.
Если это был ParallelQuery
- созданный путем вызова .AsParallel
для перечисляемой коллекции в памяти - тогда запрос будет выполнен in-memroy, распараллелен (в большинстве случаев) так, чтобы он выполнялся несколькими потоками - в идеале, каждый сердечник занят работой, продвигая работу вперед.
Очевидно, что идея в том, чтобы быть быстрее. Когда это работает хорошо, это делает.
Хотя есть и некоторые недостатки.
Во-первых, всегда есть некоторые издержки, чтобы запустить параллелизацию, даже в тех случаях, когда невозможно параллелизировать. Если над данными недостаточно работы, эти издержки перевесят любые потенциальные выгоды.
Во-вторых, преимущества параллельной обработки зависят от доступных ядер. С запросом, который не заканчивает блокировку ресурсов на 4-ядерном компьютере, теоретически вы получаете ускорение в 4 раза (4-многопотоковое может дать вам больше или даже меньше, но, вероятно, не в 8 раз, поскольку удвоение потоков в некоторых частях процессора не дает явного двукратного увеличения). С одним и тем же запросом для одноядерного процессора или с привязкой к процессору, означающим, что доступно только одно ядро (например, веб-сервер в режиме «веб-сада»), ускорение не происходит. При блокировке ресурсов все еще может быть выигрыш, но выгода зависит от машины.
В-третьих, если какой-либо общий ресурс (возможно, на который выводятся результаты коллекции) используется не потокобезопасным способом, он может пойти не так, как надо с неверными результатами, сбоями и т. Д.
В-четвертых, если совместно используемый ресурс используется в поточно-ориентированном режиме и что безопасность потоков обеспечивается за счет блокировки, может быть достаточно конфликтов, чтобы стать узким местом, которое отменяет все преимущества распараллеливания.
В-пятых, если у вас четырехъядерный компьютер, работающий на более или менее одинаковом алгоритме в четырех разных потоках (возможно, в ситуации клиент-сервер из-за четырех клиентов или в ситуации с настольным компьютером из набора похожих задач) выше), то они уже лучше всего используют эти ядра. Разделение работы алгоритма таким образом, чтобы его можно было обрабатывать по всем четырем ядрам, означает, что вы перешли с четырех потоков, используя по одному ядру, каждый на 16 потоков, сражающихся на четырех ядрах. В лучшем случае это будет то же самое, и вероятные накладные расходы сделают это немного хуже.
Это может все еще быть главной победой во многих случаях, но приведенное выше должно прояснить, что это не всегда будет.