performance - ejemplo - ¿Cómo se implementa fseek() en el sistema de archivos?
fseek c++ ejemplo (6)
(descargo de responsabilidad: solo quiero agregar algunos consejos a esta interesante discusión) En mi humilde opinión, hay algunas cosas a tener en cuenta:
1) fseek no es un servicio de sistema primario, sino una función de biblioteca. Para evaluar su rendimiento debemos considerar cómo se implementa la biblioteca de flujo de archivos. En general, la biblioteca de E / S de archivos agrega una capa de almacenamiento en búfer en el espacio del usuario, por lo que el rendimiento de fseek puede ser bastante diferente si la posición de destino está dentro o fuera del búfer actual. Además, los servicios del sistema que utiliza la biblioteca de E / S pueden variar mucho. Es decir, en algunos sistemas, la biblioteca utiliza ampliamente la asignación de memoria de archivos, si es posible.
2) Como dijiste, diferentes sistemas de archivos pueden comportarse de una manera muy diferente. En particular, espero que un sistema de archivos transaccional deba hacer algo muy inteligente y quizás costoso para estar preparado para una posible reversión de una operación de escritura abortada en medio de un archivo.
3) Los sistemas operativos modernos tienen algoritmos de almacenamiento en caché muy agresivos. Es probable que un archivo "fseeked" ya esté presente en el caché, por lo que las operaciones se vuelven mucho más rápidas. Pero pueden degradarse mucho si la actividad general del sistema de archivos producida por otros procesos se vuelve importante.
¿Algún comentario?
Esta no es una pregunta de programación pura, sin embargo, afecta el rendimiento de los programas que usan fseek (), por lo que es importante saber cómo funciona. Un pequeño descargo de responsabilidad para que no se cierre.
Me pregunto qué tan eficiente es insertar datos en la mitad del archivo. Suponiendo que tengo un archivo con datos de 1 MB y luego inserto algo en el desplazamiento de 512 KB. ¿Qué tan eficiente sería eso comparado con agregar mis datos al final del archivo? Solo para completar el ejemplo, digamos que quiero insertar 16 KB de datos.
Entiendo que la respuesta varía según el sistema de archivos, sin embargo, asumo que las técnicas utilizadas en los sistemas de archivos comunes son bastante similares y solo quiero tener la idea correcta de ello.
Asumamos el ext2 FS y el sistema operativo Linux como ejemplo. No creo que haya una diferencia de rendimiento significativa entre un inserto y un anexo. En ambos casos, se deben leer el nodo de archivos y la tabla de compensación, el sector del disco relevante asignado en la memoria, los datos actualizados y, en algún momento posterior, los datos se volverán a escribir en el disco. Lo que hará una gran diferencia de rendimiento en este ejemplo es una buena ubicación temporal y espacial al acceder a partes del archivo, ya que esto reducirá el número de combos de carga / almacenamiento.
Como dice una respuesta anterior, es posible que pueda acelerar ambas operaciones si trata con escrituras de datos que sean múltiplos exactos del tamaño del bloque del FS, en este caso, podría saltear la etapa de carga e simplemente insertar los nuevos bloques en el archivo de datos de datos. Esto no sería práctico, ya que necesitaría un acceso de bajo nivel al controlador FS, y su uso sería muy restrictivo y no portátil.
Insertar datos en la mitad del archivo es menos eficiente que agregarlos al final porque al insertar, tendría que mover los datos después del punto de inserción para dejar espacio para los datos que se insertan. Mover estos datos implicaría leerlos desde el disco, escribir los datos que se insertarán y luego escribir los datos antiguos después de los datos insertados. Así que tienes al menos una lectura y escritura adicionales al insertar.
Puede insertar datos en la mitad del archivo de manera eficiente solo si el tamaño de los datos es un múltiplo del sector del FS, pero los sistemas operativos no proporcionan dichas funciones, por lo que debe usar una interfaz de bajo nivel para el controlador del FS.
Una observación que he hecho sobre fseek
en Solaris, es que cada llamada a ella restablece el búfer de lectura del FILE
. La siguiente lectura siempre leerá un bloque completo (8K por defecto). Entonces, si tiene un montón de acceso aleatorio con lecturas pequeñas, es una buena idea hacerlo sin búfer ( setvbuf
con NULL
buffer) o incluso usar syscalls directos ( lseek
+ read
o incluso mejor pread
que es solo 1 syscall en lugar de 2). Supongo que este comportamiento será similar en otros sistemas operativos.
fseek(...)
es una llamada de biblioteca, no una llamada del sistema operativo. Es la biblioteca de tiempo de ejecución la que se ocupa de la sobrecarga real involucrada en hacer una llamada del sistema al sistema operativo, técnicamente hablando, fseek está haciendo una llamada indirecta al sistema pero en realidad no lo es (esto hace que aparezca una clara distinción entre diferencias entre una llamada de la biblioteca y una llamada del sistema). fseek(...)
es una función de entrada-salida estándar independientemente del sistema subyacente ... sin embargo ... y esto es un gran sin embargo ...
Es muy probable que el sistema operativo haya guardado en caché el archivo en su memoria del kernel, es decir, el desplazamiento directo a la ubicación en el disco donde se almacenan los 1 y 0, es a través de las capas del kernel del sistema operativo, lo más probable, un la capa más alta dentro del kernel que tendría la instantánea de qué está compuesto el archivo, es decir, los datos con independencia de lo que contiene (no importa de ninguna manera, siempre que los ''punteros'' a la estructura del disco para esa compensación la ubicación en el disco es válida!) ...
Cuando se fseek(..)
, habría una gran cantidad de encabezados, indirectamente, el kernel delegó la tarea de leer desde el disco, dependiendo de cuán fragmentado esté el archivo, podría ser teóricamente "por todas partes" , que podría ser una fseek(...)
importante en términos de tener que, desde la perspectiva de la zona de usuario, es decir, el código C haciendo un fseek(...)
, podría dispersarse por todos lados para recopilar los datos en un "una vista contigua de los datos" y, en adelante, la inserción en el medio de un archivo (recuerde que en esta etapa, el kernel tendría que ajustar la ubicación / las compensaciones en el disco del disco real para los datos) se consideraría más lento que agregar hasta el final del archivo.
La razón es bastante simple, el kernel "sabe" cuál fue el último desplazamiento, y simplemente borra el marcador EOF e inserta más datos, detrás del escenario, el kernel, tiene que asignar otro bloque de memoria para el buffer de disco con el desplazamiento ajustado a la ubicación en el disco después de un marcador EOF, una vez que se completa el agregado de datos.