2010-04-10 2 views
2

Мне была поручена перезапись некоторых библиотек, написанных на C#, так что после завершения запуска никаких распределений не будет..NET DB Query Without Allocations?

Я только что получил один проект, который выполняет некоторые запросы БД по OdbcConnection каждые 30 секунд. Я всегда использовал .ExecuteReader(), который создает OdbcDataReader. Есть ли какой-либо шаблон (например, шаблон сокета SocketAsyncEventArgs), который позволяет повторно использовать собственный OdbcDataReader? Или какой-нибудь другой умный способ избежать распределения?

Я не удосужился узнать LINQ, так как все dbs на работе основаны на Oracle и последнее, что я проверил, не было официального поставщика Linq To Oracle. Но если в Linq есть способ сделать это, я могу использовать один из сторонних.

Update:

Я не думаю, что четко определены причины требования не-Alloc. У нас есть один критический поток, и очень важно, чтобы он не зависал. Это для торгового приложения в режиме реального времени, и мы наблюдаем до 100 мс замораживания для некоторых коллекций Gen 2. (Я также слышал, что игры пишутся одинаково на C#). Существует один фоновый поток, который выполняет некоторую проверку соответствия и запускается каждые 30 секунд. Он делает запрос db прямо сейчас. Запрос довольно медленный (около 500 мс для возврата со всеми данными), но это нормально, потому что оно не мешает критическому потоку. За исключением случаев, когда рабочий поток выделяет память, это заставит GCs заморозить все потоки.

Мне сказали, что все библиотеки (включая этот) не могут выделить память после запуска. Согласен ли я с этим или нет, это требование от людей, которые подписывают чеки :).

Теперь ясно, что я могу получить данные в этом процессе без выделения. Я мог бы настроить другой процесс и подключить его к этому, используя сокет. Новые сокеты .NET 3.5 были специально оптимизированы, чтобы не выделять их вообще, используя новый шаблон SocketAsyncEventArgs. (На самом деле, мы используем их для подключения к нескольким системам и никогда не видим никаких GC из них.) Затем у вас есть предварительно выделенный массив байтов, который читает из сокета и проходит через данные, не выделяя никаких строк на этом пути. (Я не знаком с другими формами IPC в .NET, поэтому я не уверен, что распределены файлы с памятью и именованные каналы или нет).

Но если есть более быстрый способ получить этот запрос без выделения, не пройдя все эти трудности, я бы предпочел его.

+0

Каждые 30 секунд ... вероятность того, что эффект выделения на таких длинных временных промежутках очень, очень низкий. – Dykam

+2

Хмм, никаких ассигнований. Сначала удалите все строки из ваших таблиц базы данных. Вернитесь, когда вы закончите, чтобы мы могли решить проблему № 2 до 50. В конечном итоге вам придется переключиться на C++. –

ответ

3

Нельзя использовать повторно IDataReader (или OdbcDataReader или SqlDataReader или любой эквивалентный класс). Они предназначены для использования только с одним запросом. Эти объекты инкапсулируют один набор записей, поэтому, как только вы его получили и повторили, он больше не имеет смысла.

Создание считывателя данных - это невероятно дешевая операция в любом случае, исчезающе малая, в отличие от стоимости фактического выполнения запроса. Я не вижу логической причины для этого требования «без распределения».

Я бы так далеко, чтобы сказать, что это почти невозможно переписать библиотеку так, чтобы выделить никакой памяти. Даже что-то такое же простое, как бокс целое или с использованием строковой переменной, будет выделять некоторую память. Даже если было бы возможно повторно использовать читателя (чего нет, как я объяснил), ему все равно придется снова отправить запрос в базу данных, что потребует выделения памяти в форме подготовки запроса, отправки его по сети, получение результатов снова и т. д.

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

+0

Проблема заключается не в том, что для размещения самого устройства чтения данных требуется много времени. Как вы говорите, его затмевает время запроса. И как запросы, так и распределения происходят в рабочем потоке, поэтому мы не заботимся о времени, которое они берут. Но со временем «дешевые» выделения могут вызвать GC, которые заморозят все потоки, включая критические. Вероятно, выделение памяти совсем невозможно. Но см. Например: http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=4215ab9e-4181-4526-823b-d364448188b2 –

+0

Другими словами, целью является не выделение. Но никакие ассигнования на этапе непрерывной работы приложения (после запуска не завершены). –

+0

@ Майкл - но, как вы сказали, этот запрос является * частью * вашей «непрерывной операции» и запускается каждые 30 секунд. Чрезвычайно жесткие требования к производительности (12 000 TPS!) Этого приложения могут потребовать ограничения на распределение памяти, но как только вы будите запрос базы данных там, вы ударите это прямо из воды, запрос будет стоить дороже, чем GC проходить. – Aaronaught

2

Для такого требования вы уверены, что язык высокого уровня, такой как C#, является вашим выбором?
Вы не можете сказать, являются ли используемые вами функции библиотеки .NET внутренним распределением памяти или нет. Стандарт не гарантирует этого, поэтому, если они не используют распределения в текущей версии .NET framework, они могут начать делать это позже.

+0

Правда, его не всегда ясно, если библиотечная функция выделяет память на основе ее подписи. Но вы всегда можете просто поместить вызов библиотеки в новый проект и сделать 100k звонков, чтобы увидеть, есть ли какие-либо GC. Хотя, как вы сказали, они могут изменить его в другой версии рамки. C# не был моим выбором, но некоторые люди стараются следовать шаблону проектирования без распределения в ходе непрерывной фазы работы приложения с C# с успехом: http://www.microsoft.com/downloads/details.aspx?displaylang = en & FamilyID = 4215ab9e-4181-4526-823b-d364448188b2 –

+1

@ Майкл, это было для проекта, который должен обрабатывать 12 000 транзакций в секунду на одном экземпляре. Если вы разместите хотя бы один запрос к базе данных, независимо от того, как быстро он работает, вы не собираетесь делать этот тест. Запросы базы данных ** ** ** более дороги, чем распределения памяти и пропуска GC. – Aaronaught

+0

@ Майкл: В документе, на который вы ссылаетесь, говорится, что этот подход включал тесное сотрудничество с специалистами MS.Со своей стороны, я действительно сомневаюсь, что решение, описанное в статье, останется бесплатным, для меня это больше похоже на хак. Ну, вы можете попытаться избежать использования библиотечных функций _at all _... Но ваш вопрос касается функциональности, связанной с базой данных, поэтому я лично сомневаюсь, что такие довольно сложные библиотечные функции не будут выделяться изнутри. – Vlad

1

Я предлагаю вам профилировать приложение, чтобы определить, где тратится время и/или память. Не догадывайтесь - вы ошибаетесь только.

+0

Разве это не так, правила 3-7 оптимизации? (Первые два: «Не надо!» И «Нет, действительно, не надо!») – SamB

+2

@SamB: это на самом деле 4-8. 3: «Ты действительно не хотел этого делать, поэтому отменяй его, прежде чем делать что-то хуже». –