C++ 使用sendfile()通过线程或其他有效的复制文件方法复制文件
我正在尝试使用Linux系统调用C++ 使用sendfile()通过线程或其他有效的复制文件方法复制文件,c++,linux,multithreading,sendfile,C++,Linux,Multithreading,Sendfile,我正在尝试使用Linux系统调用sendfile()使用线程复制文件 我对优化代码的以下部分感兴趣: fseek(fin, size * (number) / MAX_THREADS, SEEK_SET); fseek(fout, size * (number) / MAX_THREADS, SEEK_SET); /* ... */ fwrite(buff, 1, len, fout); 代码: void* FileOperate::FileCpThread::threadCp(vo
sendfile()
使用线程复制文件
我对优化代码的以下部分感兴趣:
fseek(fin, size * (number) / MAX_THREADS, SEEK_SET);
fseek(fout, size * (number) / MAX_THREADS, SEEK_SET);
/* ... */
fwrite(buff, 1, len, fout);
代码:
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);
}
文件复制不受CPU限制;如果是这样的话,您可能会发现限制在内核级别,而在用户级别上您所能做的任何事情都不会将其并行化 在机械驱动器上进行的此类“改进”实际上会降低吞吐量。你在浪费时间查找文件,而不是读写它 如果文件很长,并且您不希望很快需要读取或写入的数据,那么在打开时可能会使用
O_DIRECT
标志。这是一个坏主意,因为O_DIRECT
API本质上是
相反,您应该在源文件和目标文件上使用posix\u fadvise
,使用posix\u FADV\u顺序和posix\u FADV\u NOREUSE标志。在write(或sendfile)调用完成后,您需要通知不再需要数据-pass POSIX_FADV_DONTNEED。这样,页面缓存将仅在保持数据流动所需的范围内使用,并且一旦数据被消耗(写入磁盘),页面将被回收
sendfile
不会将文件数据推送到用户空间,因此它进一步缓解了来自内存和处理器缓存的一些压力。这是您在复制非特定于设备的文件时可以做的唯一其他明智的改进
选择合理的块大小也是可取的。考虑到现代驱动器的速度超过100兆字节/秒,您可能希望一次推一兆字节,并且总是4096字节页面大小的倍数-因此(4096*256)
是一个不错的开始块大小,可以在单个发送文件
或读取
/写入
调用中处理
正如您所建议的,读并行化仅在RAID 0卷上有意义,并且仅当输入和输出文件都跨在物理磁盘上时才有意义。然后,您可以在文件所跨越的源卷和目标卷物理磁盘的数量中,以较小者为单位拥有一个线程。只有在不使用异步文件I/O的情况下才有必要这样做。使用异步I/O,您不需要多个线程,尤其是在块大小较大(兆字节+)且单线程延迟损失可以忽略不计的情况下
在SSD上并行单个文件拷贝没有任何意义,除非您确实在某个非常奇怪的系统上。文件拷贝不受CPU限制;如果是这样的话,您可能会发现限制在内核级别,而在用户级别上您所能做的任何事情都不会将其并行化 在机械驱动器上进行的此类“改进”实际上会降低吞吐量。你在浪费时间查找文件,而不是读写它 如果文件很长,并且您不希望很快需要读取或写入的数据,那么在打开时可能会使用
O_DIRECT
标志。这是一个坏主意,因为O_DIRECT
API本质上是
相反,您应该在源文件和目标文件上使用posix\u fadvise
,使用posix\u FADV\u顺序和posix\u FADV\u NOREUSE标志。在write(或sendfile)调用完成后,您需要通知不再需要数据-pass POSIX_FADV_DONTNEED。这样,页面缓存将仅在保持数据流动所需的范围内使用,并且一旦数据被消耗(写入磁盘),页面将被回收
sendfile
不会将文件数据推送到用户空间,因此它进一步缓解了来自内存和处理器缓存的一些压力。这是您在复制非特定于设备的文件时可以做的唯一其他明智的改进
选择合理的块大小也是可取的。考虑到现代驱动器的速度超过100兆字节/秒,您可能希望一次推一兆字节,并且总是4096字节页面大小的倍数-因此(4096*256)
是一个不错的开始块大小,可以在单个发送文件
或读取
/写入
调用中处理
正如您所建议的,读并行化仅在RAID 0卷上有意义,并且仅当输入和输出文件都跨在物理磁盘上时才有意义。然后,您可以在文件所跨越的源卷和目标卷物理磁盘的数量中,以较小者为单位拥有一个线程。只有在不使用异步文件I/O的情况下才有必要这样做。使用异步I/O,您不需要多个线程,尤其是在块大小较大(兆字节+)且单线程延迟损失可以忽略不计的情况下
在SSD上并行单个文件拷贝没有任何意义,除非您确实在某个非常奇怪的系统上。文件拷贝不受CPU限制;如果是这样的话,您可能会发现限制在内核级别,而在用户级别上您所能做的任何事情都不会将其并行化 在机械驱动器上进行的此类“改进”实际上会降低吞吐量。你在浪费时间查找文件,而不是读写它 如果文件很长,并且您不希望很快需要读取或写入的数据,那么在打开时可能会使用
O_DIRECT
标志。这是一个坏主意,因为O_DIRECT
API本质上是
相反,您应该在源文件和目标文件上使用posix\u fadvise
,使用posix\u FADV\u顺序和posix\u FADV\u NOREUSE标志。在write(或sendfile)调用完成后,您需要通知不再需要数据-pass POSIX_FADV_DONTNEED。这样,页面缓存将仅在保持数据流动所需的范围内使用,并且一旦数据被消耗(写入磁盘),页面将被回收
sendfile
不会将文件数据推送到用户spa