Заставить Linq не задерживать выполнение

На самом деле, это тот же вопрос, что и этот пост:

Как я могу убедиться, что мои запросы LINQ выполняются при вызове в моем DAL, а не с задержкой?

Но поскольку он не объяснил, почему ему это нужно, вопрос, кажется, был немного упущен. Вот моя похожая, но лучше объясненная проблема:

У меня есть несколько потоков двух типов (ненадолго игнорируя потоки пользовательского интерфейса). Существует тип потока «сбор данных» и тип потока «вычисления». Потоки сбора данных работают медленно. Есть довольно много данных, которые нужно просеять из разных мест. Вычислительные потоки сравнительно быстрые. Модель проектирования до этого момента заключалась в том, чтобы отправлять потоки сбора данных для поиска данных, а когда они завершены, передавать данные для вычислений.

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

Я хотел бы заставить Linq завершить свою работу в заданное время (конец инструкции? конец метода? вызов метода «пожалуйста, закончи, черт возьми»), чтобы я знал, что не буду платить за это позже. Добавление «.ToList()» в конец Linq 1. неудобно и 2. похоже на упаковку чего-то, что в любом случае будет распаковано в другом потоке.


person Clinton Pierce    schedule 30.06.2009    source источник
comment
Помните: ценность понимания запроса — это объект, который представляет сам запрос, а не его результаты. Если вам нужен моментальный снимок результатов, вам придется каким-то образом запросить их у объекта запроса (а затем смириться с тем фактом, что они могут устареть к тому времени, когда вы их используете). ToList выглядит как самый простой способ сделать это.   -  person Eric Lippert    schedule 30.06.2009


Ответы (4)


Вы бы ничего не упаковывали - вы бы буферизовали результаты.

Использование ToList() - это в основном путь, если вам действительно нужны данные. Если вы не готовы использовать данные немедленно, их нужно где-то буферизовать, не так ли? Список — это просто удобный способ сделать это.

Альтернатива состоит в том, чтобы выполнять обработку тут же и там же — использовать данные по мере их создания, жадно. Я не совсем следил за разными потоками, поэтому мне не ясно, поможет ли это вам, но, насколько я вижу, это в основном доступные вам варианты.

На самом деле это несколько явно указано в вашем описании:

Модель проектирования до этого момента заключалась в том, чтобы отправлять потоки сбора данных для поиска данных, а когда они завершены, передавать данные для вычислений.

Вызов ToList() в основном меняет то, что вы возвращаете, с «запроса, который может извлекать данные по запросу» на «сами данные, буферизованные в списке».

person Jon Skeet    schedule 30.06.2009
comment
Или вызов любого метода для результата, такого как Count(), должен делать то же самое... - person GalacticCowboy; 30.06.2009
comment
Это заставит его оценить, но в противном случае данные снова будут потеряны - если исходный запрос затем будет передан обратно, все это будет оцениваться снова, предположительно медленно. - person Jon Skeet; 30.06.2009
comment
@GalacticCowboy: вызов такого метода, как Count, буферизует результаты, но затем они будут отброшены, и вы просто останетесь со счетом и без данных :( - person LukeH; 30.06.2009
comment
@Luke: нет причин, по которым Count() должен буферизовать результаты. Он будет вычислять результаты, но может отбрасывать их так же быстро, как они получены. Например, если у вас есть источник данных, который возвращает каждую строку журнала в гигантском файле, вы можете вызвать Count() без нехватки памяти, но ToList() потребует, чтобы все строки находились в памяти одновременно. - person Jon Skeet; 30.06.2009
comment
@Jon: Хороший вопрос. Я пытался подчеркнуть, что использование Count приведет к отбрасыванию данных, но я должен был сказать, что может буферизоваться... а не буферизоваться.... - person LukeH; 30.06.2009
comment
Поисковые термины Eager и Lazy, кажется, дают мне дополнительные возможности для поиска. Все еще ищу. - person Clinton Pierce; 30.06.2009
comment
@clintp: Я сильно подозреваю, что вы все еще ищете что-то, что невозможно сделать, исходя из того, что вы здесь описали. Вы хотите, чтобы информация была доступна немедленно, когда вы используете ее из потока вычислений, но вы не хотите сохранять ее между моментом, когда вы ее извлекаете в потоке чтения данных, и временем, когда вы ее обрабатываете. Без его хранения, как вы ожидаете, что сможете быстро получить его снова? - person Jon Skeet; 30.06.2009
comment
Хорошо, я смешала яблоки и апельсины. Комментарий Эрика выше разъяснил, в чем заключалась моя проблема: одно из ожиданий. Если ToList() — самый простой способ упаковать эти результаты, то я так и сделаю. - person Clinton Pierce; 30.06.2009
comment
@Jon: Но Count — это самый дешевый способ заставить запрос LINQ выполняться полностью, не так ли? Потому что Any(без параметра) выполнит только одну итерацию. Я спрашиваю, потому что единственной целью запроса может быть итеративное выполнение методов, как в этом примере (VB.NET): Dim c = (From y In {2012, 2011, 2010} Select tbl.Rows.Add(y)).Count (где tbl - это DataTable с одним столбцом). - person Tim Schmelter; 26.01.2012
comment
@TimSchmelter: это не обязательно заставляет запрос выполняться полностью - например, он может просто попросить базу данных найти количество. Если OP хочет результатов (как это звучит), простой вызов Count не принесет никакой пользы. - person Jon Skeet; 26.01.2012
comment
@Jon: Мой вопрос не был напрямую связан с этим вопросом, а скорее с вашим ответом на первый комментарий от GalacticCowboy. На самом деле я только что задал вопрос, который, к сожалению, оказался не таким полезным, как я надеялся: stackoverflow.com/questions/9010639/ - person Tim Schmelter; 26.01.2012
comment
@TimSchmelter: Было довольно сложно ответить на такой общий вопрос без контекста :) Стоит отметить, что то, что вы делаете в этом вопросе, в основном плохая идея - запросы не должны иметь побочных эффектов. Если бы вы не добавили побочный эффект в запрос, у вас не было бы проблемы... - person Jon Skeet; 26.01.2012

Можете ли вы объяснить, почему .ToList неприемлем? Вы упомянули бокс и распаковку, но это совершенно не связанные темы.

Часть принудительного выполнения запроса LINQ по запросу требует сохранения результатов. В противном случае, чтобы снова увидеть результаты, вам придется повторно обработать запрос. .ToList эффективно достигает этого, сохраняя элементы в List<T>.

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

person JaredPar    schedule 30.06.2009
comment
Читай внимательно. Это по ощущениям похоже на упаковку/распаковку. Назовите это инкапсуляцией, подарочной упаковкой или чем-то еще. - person Clinton Pierce; 30.06.2009
comment
@clintp, извини, мне кажется, что это неудачные сравнения. - person JaredPar; 30.06.2009

В классе DataContext есть свойство LoadOptions, которое поможет вам быстрее получать данные.

В противном случае вы могли бы использовать несколько умно размещенных ToList().

person leppie    schedule 30.06.2009

Я знаю, что эта ветка устарела... во всяком случае, забавно, что никто еще не упомянул .ToLast(). Я делаю что-то, где linq не намного больше, чем прославленный foreach, управляющий некоторыми побочными эффектами, когда меня не волнует результат запроса... поэтому я не хотел выделять больше фиктивной памяти, чем необходимо.

person Brent Anderson    schedule 09.02.2011