Я создаю игрушечную базу данных в C #, чтобы узнать больше о компиляторе, оптимизаторе и технологии индексирования.
Я хочу поддерживать максимальный параллелизм между (по крайней мере, чтением) запросов на перенос страниц в буферный пул, но я не понимаю, как лучше всего это сделать в .NET.
Вот несколько вариантов и проблем, с которыми я сталкивался:
Используйте System.IO.FileStream
и метод BeginRead
Но позиция в файле не является аргументом для BeginRead
, это свойство FileStream
(устанавливается с помощью метода Seek
), поэтому я могу выдавать только один запрос за раз и должны заблокировать поток на время. (Или я? В документации неясно, что произойдет, если я удерживаю блокировку только между вызовами Seek
и BeginRead
, но снимаю ее до вызова EndRead
. Кто-нибудь знает?) Я знаю, как это сделать, Я просто не уверен, что это лучший способ.
Кажется, есть другой способ, сосредоточенный вокруг структуры System.Threading.Overlapped
и P \ Invoke для функции ReadFileEx
в kernel32.dll.
К сожалению, не хватает примеров, особенно в управляемых языках. Этот маршрут (если его вообще можно заставить работать), по-видимому, также включает метод ThreadPool.BindHandle
и потоки завершения ввода-вывода в пуле потоков. У меня складывается впечатление, что это санкционированный способ работы с этим сценарием в Windows, но я его не понимаю и не могу найти точку входа в документацию, полезную для непосвященных.
Что-то еще?
В комментарии jacob предлагает создать новое FileStream
для каждого чтения в полете.
Считать весь файл в память.
Это будет работать, если база данных будет маленькой. Кодовая база небольшая, и есть много других недостатков, но сама база данных не так. Я также хочу быть уверен, что я веду всю бухгалтерию, необходимую для работы с большой базой данных (которая оказывается огромной частью сложности: подкачка страниц, внешняя сортировка, ...), и я боюсь, что это может быть слишком легко обмануть случайно.
Редактировать
Разъяснение того, почему я с подозрением отношусь к решению 1: удержание одной блокировки на всем пути от BeginRead до EndRead означает, что мне нужно заблокировать любого, кто хочет инициировать чтение, только потому, что выполняется другое чтение. Это кажется неправильным, потому что поток, инициирующий новое чтение, может (в целом) выполнить еще некоторую работу до того, как результаты станут доступны. (На самом деле, просто написание этого текста заставило меня придумать новое решение, я поставил новый ответ.)