Use sendfile() para copiar o arquivo com threads ou outros eficiente método de cópia de arquivo

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

Pergunta

Estou tentando usar o sistema Linux chamada sendfile() para copiar um arquivo usando threads.

Eu estou interessado na otimização de partes do 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);
}
Foi útil?

Solução

A cópia de arquivo não é CPU bound;se fosse você é provável encontrar que a limitação é no nível do kernel e nada que você pode fazer com o usuário leve iria colocar em paralelo a ele.

Tais "melhorias" feito em acionamentos mecânicos de fato degradar a taxa de transferência.Você está desperdiçando o tempo de busca ao longo do arquivo, em vez de ler e de escrever.

Se o ficheiro for grande e você não espera necessário a leitura ou a escrita de dados a qualquer momento em breve, pode ser tentador usar o O_DIRECT sinalizador em abrir.Isso é uma má idéia, desde que o O_DIRECT API é essencialmente quebrado pelo design.

Em vez disso, você deve usar posix_fadvise em ambos os arquivos de origem e destino, com POSIX_FADV_SEQUENTIAL e POSIX_FADV_NOREUSE bandeiras.Após a gravação (ou sendfile) a chamada é concluída, é necessário informar que os dados não é mais necessário - passar POSIX_FADV_DONTNEED.Dessa forma, a página de cache só será usada na medida do necessário para manter os dados que fluem, e as páginas serão reciclados assim que os dados tiverem sido consumida (gravados em disco).

O sendfile não empurre arquivo de dados para o espaço de usuário, então é mais relaxa um pouco a pressão de memória e cache de processador.Essa é a única outros sensível melhoria que você pode fazer para cópia de arquivos que não é específico de dispositivo.

A escolha de um adequado tamanho de bloco também é desejável.Dado que as modernas unidades de empurrar mais de uma 100Mbytes/s, você pode querer empurrar um megabyte de cada vez, e sempre um múltiplo de 4096 bytes, o tamanho de página - assim (4096*256) é uma partida decente tamanho do bloco de processar em uma única sendfile ou read/write chamadas.

Leia paralelização, como você propô-la, só faz sentido em RAID 0 volumes, e apenas quando ambos os arquivos de entrada e saída de straddle os discos físicos.Em seguida, você pode ter uma thread por menor que o número de volumes de origem e destino discos físicos assentado pelo arquivo.Isso é necessário somente se você não estiver usando assíncrona e/S de arquivoCom e/S assíncrona você não precisa de mais do que um thread de qualquer maneira, especialmente se o trecho tamanhos são grandes (megabyte+) e o single-thread latência pena é insignificante.

Não há sentido para a paralelização de um único ficheiro de cópia de SSDs, a menos que você estava muito estranho sistema de fato.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top