Verwenden Sie sendfile(), um Dateien mit Threads oder einer anderen effizienten Methode zum Kopieren von Dateien zu kopieren

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

Frage

Ich versuche, den Linux-Systemaufruf zu verwenden sendfile() um eine Datei mithilfe von Threads zu kopieren.

Ich bin daran interessiert, diese Teile des Codes zu optimieren:

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

Code:

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);
}
War es hilfreich?

Lösung

Das Kopieren von Dateien ist nicht CPU-gebunden;Wäre dies der Fall, würden Sie wahrscheinlich feststellen, dass die Einschränkung auf Kernel-Ebene liegt und nichts, was Sie auf Benutzerebene tun können, sie parallelisieren würde.

Solche „Verbesserungen“ an mechanischen Antrieben werden tatsächlich durchgeführt degradieren der Durchsatz.Sie verschwenden Zeit damit, die Datei zu durchsuchen, anstatt sie zu lesen und zu schreiben.

Wenn die Datei lang ist und Sie nicht damit rechnen, die gelesenen oder geschriebenen Daten bald zu benötigen, könnte es verlockend sein, die zu verwenden O_DIRECT Flagge auf offen.Das ist eine schlechte Idee, denn die O_DIRECT API ist im Wesentlichen vom Design her gebrochen.

Stattdessen sollten Sie verwenden posix_fadvise sowohl für Quell- als auch für Zieldateien, mit den Flags POSIX_FADV_SEQUENTIAL und POSIX_FADV_NOREUSE.Nachdem der Aufruf write (oder sendfile) abgeschlossen ist, müssen Sie mitteilen, dass die Daten nicht mehr benötigt werden – übergeben Sie POSIX_FADV_DONTNEED.Auf diese Weise wird der Seitencache nur in dem Umfang verwendet, der für den Datenfluss erforderlich ist, und die Seiten werden recycelt, sobald die Daten verbraucht (auf die Festplatte geschrieben) wurden.

Der sendfile Dateidaten werden nicht in den Benutzerbereich verschoben, wodurch die Belastung durch Arbeitsspeicher und Prozessor-Cache weiter verringert wird.Das ist ungefähr die einzige weitere sinnvolle Verbesserung, die Sie beim Kopieren von Dateien vornehmen können, die nicht gerätespezifisch sind.

Wünschenswert ist auch die Wahl einer sinnvollen Stückgröße.Angesichts der Tatsache, dass moderne Laufwerke über 100 MB/s übertragen, möchten Sie möglicherweise jeweils ein Megabyte und immer ein Vielfaches der Seitengröße von 4096 Byte übertragen (4096*256) ist eine anständige Anfangsstückgröße, die man in einem einzigen Stück verarbeiten kann sendfile oder read/write Anrufe.

Die von Ihnen vorgeschlagene Leseparallelisierung ist nur auf RAID 0-Volumes sinnvoll und nur dann, wenn sich sowohl die Eingabe- als auch die Ausgabedateien über die physischen Festplatten erstrecken.Sie können dann einen Thread für die kleinere der beiden physischen Festplatten des Quell- und Ziel-Volumes verwenden, über die sich die Datei erstreckt.Dies ist nur erforderlich, wenn Sie keine asynchrone Datei-E/A verwenden.Mit asynchroner E/A benötigen Sie ohnehin nicht mehr als einen Thread, insbesondere nicht, wenn die Blockgrößen groß sind (Megabyte+) und die Latenzstrafe für einen einzelnen Thread vernachlässigbar ist.

Es macht keinen Sinn, eine einzelne Dateikopie auf SSDs zu parallelisieren, es sei denn, Sie befinden sich tatsächlich auf einem sehr seltsamen System.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top