Estoy creando una base de datos de juguetes en C# para obtener más información sobre el compilador, el optimizador y la tecnología de indexación.Archivo asíncrono IO en .Net
Quiero mantener el máximo paralelismo entre las solicitudes (al menos de lectura) para traer páginas al grupo de búferes, pero estoy confundido sobre la mejor manera de lograr esto en .NET.
Estas son algunas de las opciones y los problemas que he encontrado con cada uno:
Use
System.IO.FileStream
y el métodoBeginRead
Pero, la posición en el archivo no es un argumento aBeginRead
, es una propiedad delFileStream
(establecida a través del métodoSeek
), por lo que solo puedo emitir una solicitud a la vez y bloquear la transmisión durante ese tiempo. (¿O sí?) La documentación no está clara de lo que sucedería si mantuviera el bloqueo solo entre las llamadasSeek
yBeginRead
, pero lo solté antes de llamar alEndRead
. ¿Alguien sabe?) Sé cómo hacer esto, no estoy seguro es la mejor manera.Parece haber otra forma, centrada en la estructura
System.Threading.Overlapped
y P \ Invocar a la funciónReadFileEx
en kernel32.dll.Desafortunadamente, hay pocas muestras, especialmente en idiomas administrados. Esta ruta (si se puede hacer que funcione) aparentemente también involucra el método
ThreadPool.BindHandle
y los hilos de terminación de E/S en el grupo de subprocesos. Me da la impresión de que esta es la forma aprobada de tratar este escenario bajo Windows, pero no lo entiendo y no puedo encontrar un punto de entrada a la documentación que sea útil para los no iniciados.¿Algo más?
En un comentario, jacob sugiere crear un nuevo
FileStream
por cada lectura en vuelo.Lea todo el archivo en la memoria.
Esto funcionaría si la base de datos fuera pequeña. La base de código es pequeña, y hay muchas otras ineficiencias, pero la base de datos no lo es. También quiero asegurarme de que estoy haciendo toda la contabilidad necesaria para manejar una gran base de datos (que resulta ser una gran parte de la complejidad: paginación, clasificación externa, ...) y me preocupa que sea demasiado fácil de engañar accidentalmente.
Editar
aclaración de por qué estoy sospechoso con una solución 1: celebración de una sola cerradura hasta el final de BeginRead a EndRead significa que tengo que bloquear cualquier persona que quiera iniciar una lectura sólo porque otra lectura está en progreso. Eso se siente mal, porque el hilo que inicia la nueva lectura podría (en general) hacer un poco más de trabajo antes de que los resultados estén disponibles. (En realidad, simplemente escribir esto me ha llevado a pensar en una nueva solución, puse como una nueva respuesta.)
Esta es una buena idea. También puede evitar asignar nuevos bytes [] s (y agolpamiento del montón de objetos grandes) preasignándolos en grandes fragmentos al crear (o hacer crecer) el grupo de búferes. –
Además, ahora no me refería al GetQueuedCompletionStatus (o lo leí de alguna manera), lo que probablemente explica por qué fracasaron mis intentos. Es hora de leer un poco más. –