Use sendfile() para copiar o arquivo com threads ou outros eficiente método de cópia de arquivo
-
21-12-2019 - |
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);
}
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.