Utilice sendfile() para copiar archivos con subprocesos u otro método eficiente para copiar archivos

StackOverflow https://stackoverflow.com//questions/25031044

Pregunta

Estoy intentando utilizar la llamada al sistema Linux. sendfile() para copiar un archivo usando hilos.

Estoy interesado en optimizar estas partes del código:

fseek(fin, size * (number) / MAX_THREADS, SEEK_SET);  
fseek(fout, size * (number) / MAX_THREADS, SEEK_SET); 
/* ... */
fwrite(buff, 1, len, fout);  

Código:

void* FileOperate::FileCpThread::threadCp(void *param)
{
    Info *ft = (Info *)param;
    FILE *fin = fopen(ft->fromfile, "r+");
    FILE *fout = fopen(ft->tofile, "w+");

    int size = getFileSize(ft->fromfile);

    int number =  ft->num;
    fseek(fin, size * (number) / MAX_THREADS, SEEK_SET);
    fseek(fout, size * (number) / MAX_THREADS, SEEK_SET);

    char buff[1024] = {'\0'};
    int len = 0;
    int total = 0;

    while((len = fread(buff, 1, sizeof(buff), fin)) > 0)
    {
        fwrite(buff, 1, len, fout);
        total += len;

        if(total > size/MAX_THREADS)
        {
            break;
        }
    }

    fclose(fin);
    fclose(fout);
}
¿Fue útil?

Solución

La copia de archivos no está vinculada a la CPU;si así fuera, probablemente encontraría que la limitación está en el nivel del kernel y nada de lo que pueda hacer en el nivel del usuario la paralelizaría.

De hecho, estas "mejoras" realizadas en los accionamientos mecánicos degradar el rendimiento.Está perdiendo el tiempo buscando el archivo en lugar de leerlo y escribirlo.

Si el archivo es largo y no espera necesitar los datos leídos o escritos en el corto plazo, puede resultar tentador utilizar el O_DIRECT bandera en abierto.Esa es una mala idea, ya que el O_DIRECT API es esencialmente roto por diseño.

En su lugar, deberías utilizar posix_fadvise en archivos de origen y de destino, con indicadores POSIX_FADV_SEQUENTIAL y POSIX_FADV_NOREUSE.Una vez finalizada la llamada de escritura (o envío de archivo), debe informar que los datos ya no son necesarios; pase POSIX_FADV_DONTNEED.De esa manera, la caché de páginas solo se utilizará en la medida necesaria para mantener el flujo de datos y las páginas se reciclarán tan pronto como los datos se hayan consumido (escritos en el disco).

El sendfile no enviará datos de archivos al espacio del usuario, por lo que alivia aún más parte de la presión de la memoria y el caché del procesador.Ésta es la única mejora sensata que puede realizar para copiar archivos que no sean específicos del dispositivo.

También es aconsejable elegir un tamaño de trozo razonable.Dado que las unidades modernas transmiten más de 100 Mbytes/s, es posible que desee enviar un megabyte a la vez, y siempre un múltiplo del tamaño de página de 4096 bytes; por lo tanto, (4096*256) es un tamaño de fragmento inicial decente para manejar en un solo sendfile o read/write llamadas.

La paralelización de lectura, tal como la propone, solo tiene sentido en volúmenes RAID 0, y solo cuando los archivos de entrada y salida se encuentran entre los discos físicos.Luego puede tener un subproceso por cada número menor de discos físicos de volumen de origen y de destino que se encuentren entre el archivo.Esto solo es necesario si no está utilizando E/S de archivos asíncronos.De todos modos, con E/S asíncrona no necesitaría más de un subproceso, especialmente si los tamaños de los fragmentos son grandes (megabytes+) y la penalización de latencia de un solo subproceso es insignificante.

No tiene sentido paralelizar una copia de un solo archivo en SSD, a menos que esté en algún sistema muy extraño.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top