todos - mover varios archivos en linux
¿Linux tiene cero copia? empalme o enviar archivo? (2)
De acuerdo con la página del manual correspondiente en splice a partir del 2014-07-08, cito:
Aunque hablamos de copiar, generalmente se evitan las copias reales. El kernel hace esto al implementar un búfer de tubería como un conjunto de punteros contados de referencia a las páginas de la memoria del kernel. El kernel crea "copias" de páginas en un búfer creando nuevos punteros (para el búfer de salida) que se refieren a las páginas, y aumenta el número de referencias para las páginas: solo se copian los punteros, no las páginas del búfer.
Por lo tanto, sí, se documenta que el empalme es actualmente una copia cero en la mayoría de los casos.
Cuando se introdujo el empalme, se discutió en la lista del kernel que el archivo de envío se reimplementó basándose en el empalme. La documentación para empalme SLICE_F_MOVE indica:
Intenta mover páginas en lugar de copiar. Esto es solo una sugerencia para el kernel: las páginas aún pueden copiarse si el kernel no puede mover las páginas de la tubería, o si los búferes de tubería no se refieren a páginas completas. La implementación inicial de este indicador fue defectuosa: por lo tanto, a partir de Linux 2.6.21 es un no-op (pero aún está permitido en una llamada splice ()); en el futuro, una implementación correcta puede ser restaurada.
Entonces, ¿eso significa que Linux no tiene un método de copia cero para escribir en sockets? ¿O fue arreglado en algún momento y nadie actualizó la documentación durante años? ¿Tiene el archivo de envío o el empalme una implementación de copia cero en alguna de las últimas versiones del kernel 3.x?
Dado que Google no tiene respuesta a esta consulta, estoy creando una pregunta de stackoverflow para el próximo idiota que quiere saber si hay algún beneficio al usar vmsplice y splice o sendfile en lugar de la escritura antigua.
sendfile
ha sido desde entonces, y sigue siendo una copia cero (suponiendo que el hardware lo permita, pero ese suele ser el caso). Ser copia cero era el punto central de tener esta llamada en primer lugar. sendfile
se implementa hoy en día como una envoltura alrededor de splice
.
Eso sugiere que el splice
también es una copia cero, y este es el caso. Al menos en teoría, y al menos en algunos casos. El problema es averiguar cómo usarlo correctamente para que funcione de manera confiable y que sea una copia cero. La documentación es ... escasa, por decir lo menos.
En particular, el splice
solo funciona con copia cero si las páginas se entregaron como "regalo", es decir, ya no las posee (formalmente, pero en realidad aún lo hace). Eso no es un problema si simplemente empalma un descriptor de archivo en un socket, pero es un gran problema si quiere unir datos del espacio de direcciones de su aplicación, o de una tubería a otra. No está claro qué hacer con las páginas después (y cuándo). La documentación indica que no puede tocar las páginas después o hacer nada con ellas, nunca, nunca nunca. Entonces, si sigue la letra de la documentación, debe perder la memoria.
Obviamente, eso no es correcto (no puede ser ), pero no hay una buena manera de saber (¡al menos para usted!) Cuándo es seguro reutilizar o liberar esa memoria. El kernel que realiza un sendfile
lo sabría, ya que tan pronto como recibe el ACK de TCP, sabe que nunca más se necesitan los datos. El problema es que nunca puedes ver un ACK. Todo lo que sabe cuando ha devuelto el splice
es que los datos han sido aceptados para ser enviados (pero no tiene idea si ya se ha enviado o recibido, ni cuándo ocurrirá esto).
Lo que significa que necesita resolver esto de alguna manera en una capa de aplicación, ya sea haciendo ACKs manuales (se ofrece de forma gratuita con UDP confiable) o asumiendo que si la otra parte envía una respuesta a su solicitud, obviamente deben haber recibido la solicitud. .
Otra cosa que tienes que gestionar es el espacio de tubería finito. El valor predeterminado es muy pequeño, pero incluso si aumenta el tamaño, no puede simplemente empalmar ingenuamente un archivo de cualquier tamaño. sendfile
de sendfile
por otro lado, te permitirá hacer eso, lo cual es genial.
En general, sendfile
es bueno porque simplemente funciona, y funciona bien , y no necesita preocuparse por ninguno de los detalles anteriores. No es una panacea, pero seguro que es una gran adición.
Personalmente, me mantendría alejado del splice
y de su familia hasta que todo sea revisado y hasta que esté 100% claro de lo que tiene que hacer (y cuándo) y de lo que no tiene que hacer.
Las ganancias reales y efectivas sobre la write
antigua son marginales para la mayoría de las aplicaciones, de todos modos. Recuerdo algunos comentarios poco amables por parte del Sr. Torvalds hace unos años (cuando BSD tenía una forma de write
que haría algo de magia con la reasignación de páginas para obtener una copia cero, y Linux no) que señalaba que hacer una copia por lo general no es un problema, pero jugar trucos con páginas es [no lo repetiré aquí] .