¿Cómo implemento un búfer FIFO al que puedo agregar de manera eficiente trozos de bytes de tamaño arbitrario al jefe y desde el cual puedo extraer fragmentos de bytes arbitrariamente dimensionados desde la cola ?Cola FIFO eficiente para trozos de bytes de tamaño arbitrario en Python
Antecedentes:
tengo una clase que lee bytes de objetos de archivo-como en trozos de tamaño arbitrario y es en sí mismo un objeto de fichero del cual los clientes pueden leer los bytes en trozos de tamaño arbitrario.
La forma en que tengo esto implementado es que cada vez que un cliente quiere leer un trozo de bytes, la clase lee repetidamente de los objetos subyacentes tipo archivo (con tamaños de fragmentos apropiados para esos objetos) y agrega los bytes al encabezado de una cola FIFO hasta que haya suficientes bytes en la cola para servir un trozo del tamaño solicitado al cliente. A continuación, coloca esos bytes fuera de la cola de la cola y los devuelve al cliente.
Tengo un problema de rendimiento que ocurre cuando el tamaño del fragmento para los objetos subyacentes tipo archivo es mucho mayor que el tamaño del fragmento que usan los clientes cuando leen de la clase.
Supongamos que el tamaño del fragmento para los objetos subyacentes tipo archivo es de 1 MiB y el tamaño del fragmento con el que el cliente lee es de 1 KiB. La primera vez que el cliente solicita 1 KiB, la clase debe leer 1 MiB y agregarlo a la cola FIFO. Luego, para esa solicitud y las 1023 solicitudes subsiguientes, la clase debe mostrar 1 KiB en la cola de la cola FIFO, que disminuye gradualmente en tamaño de 1 MiB a 0 bytes, en cuyo momento el ciclo comienza de nuevo.
Actualmente lo he implementado con un objeto StringIO. Escribir nuevos bytes al final del objeto StringIO es rápido, pero la eliminación de bytes desde el principio es muy lenta, porque se debe crear un nuevo objeto StringIO, que contenga una copia de todo el búfer anterior menos el primer fragmento de bytes.
ASÍ QUE las preguntas que tratan problemas similares tienden a apuntar al contenedor deque. Sin embargo, deque se implementa como una lista doblemente vinculada. Escribir un fragmento para el deque requeriría dividir el fragmento en objetos, cada uno con un solo byte. El deque luego agregaría dos punteros a cada objeto para almacenar, probablemente aumentando los requisitos de memoria al menos en un orden de magnitud en comparación con los bytes. Además, tomaría mucho tiempo recorrer la lista enlazada y tratar con cada objeto para dividir los fragmentos en objetos y unir los objetos en trozos.
Ooh, +1 para el envolvente. No había pensado en eso. Sin embargo, necesitaría saber el tamaño máximo por adelantado; de hecho, supongo que se podría cultivar según sea necesario ... – Cameron
¡Gracias! Esto se ve perfecto. Hice un experimento con StringIO que indica que se expandirá automáticamente para acomodar esto. Por ejemplo, si el tamaño actual del objeto StringIO es de 10 bytes y PUTPT (la ubicación de búsqueda) está en el índice 5, escribir un fragmento de 20 bytes expande automáticamente el objeto StringIO a 25 bytes, conservando los primeros 5 bytes y sobrescribiendo el resto. Sin embargo, si GETPT está actualmente después de PUTPT, se requiere algo más de lógica. –
Implementé esta idea en mi respuesta a continuación. ¡Aclamaciones! – Cameron