Utilizzare SendFile () per copiare il file con i thread o altri metodi di file di copia efficienti

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

Domanda

Sto cercando di utilizzare la chiamata di sistema Linux sendfile() per copiare un file usando i thread.

Sono interessato ad ottimizzare queste parti del codice:

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

Codice:

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);
}
.

È stato utile?

Soluzione

La copia del file non è vincolata della CPU; Se fosse probabile che scopresse che la limitazione è a livello del kernel e nulla che tu possa fare all'utente Leve lo avrebbe parallelizzabile.

Tali "miglioramenti" effettuati su unità meccaniche saranno infatti degradali il throughput. Stai perdendo tempo a cercare lungo il file invece di leggere e scriverlo.

Se il file è lungo e non si prevede di aver bisogno dei dati di lettura o scritta in qualsiasi momento presto, potrebbe essere tentato di utilizzare il flag O_DIRECT su Aperto. Questa è una cattiva idea, dal momento che l'API O_DIRECT è essenzialmente rotto da Design .

Invece, è necessario utilizzare posix_fadvise su entrambi i file di origine e di destinazione, con i flag posix_fadv_equestrale e posix_fadv_noreuse. Dopo aver finito la chiamata WRITE (o SENDFILE), è necessario avvisare che i dati non sono necessari più - Pass posix_Fadv_dontNeed. In questo modo la cache della pagina verrà utilizzata solo nella misura necessaria per mantenere il flusso dei dati e le pagine verranno riciclate non appena i dati sono stati consumati (scritto su disco).

Il sendfile non spingerà i dati del file sullo spazio utente, quindi rilassa ulteriormente parte della pressione dalla memoria e dalla cache del processore. Si tratta di un altro altro miglioramento sensato che puoi fare per la copia di file non specifici del dispositivo.

La scelta di una dimensione sensata del pezzo è anche auspicabile. Dato che le unità moderne spingevano oltre un 100mbytes / s, potresti voler premere un megabyte alla volta, e sempre un multiplo della dimensione della pagina di 4096 byte - quindi (4096*256) è una dimensione di avviamento decente da maneggiare in un singolo sendfile o read / write Calls.

Leggi la parallelizzazione, mentre lo proponi, ha senso solo sui volumi RAID 0, e solo quando entrambi i file di input e output strofinano i dischi fisici. È quindi possibile disporre di un thread per il minore del numero di dischi fisici del volume di origine e di destinazione a Straddled dal file. Questo è solo necessario se non stai usando il file asincrono I / O. Con Async I / O non avresti bisogno di più di un thread comunque, specialmente se le dimensioni del blocco sono grandi (megabyte +) e la penalità di latenza a filo singolo è trascurabile.

Non c'è senso per la parallelizzazione di una singola copia di file su SSD, a meno che tu non fosse in effetti un sistema molto dispari.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top