由于想加速今天使用了mmap来写一个复制文件的程序,发现原来使用mmap来复制文件原来是不够直接用read和write来复制文件快的
也许有人会觉得我不对,不过我首先说明复制背景:
我的复制文件不像《UNIX网络编程卷2》上面说的那样,有一个客户端和一个服务端进程,我的只有一个进程,在这一个进程内进行复制操作。
首先列出一下我写的两个复制文件的函数:
使用mmap复制的函数:
static int copyfile(const char * source, const char * destination, int mode) {
int fd_r, fd_w;
struct stat file_stat;
ssize_t file_len;
char *file_buf_r, *file_buf_w;
if (0 == mode) {
mode = 0660;
}
fd_r = open(source, O_RDONLY);
if (fd_r < 0) {
return 1;
}
if (fstat(fd_r, &file_stat) < 0) {
close(fd_r);
return 1;
}
file_len = file_stat.st_size;
file_buf_r = (char *) mmap(NULL, file_len, PROT_READ, MAP_SHARED, fd_r,
SEEK_SET);
if (file_buf_r == MAP_FAILED) {
close(fd_r);
return 1;
}
close(fd_r);
fd_w = open(destination, O_CREAT | O_RDWR, mode);
if (fd_w < 0) {
close(fd_r);
munmap(file_buf_r, file_len);
return 1;
}
if (ftruncate(fd_w, file_len) < 0) {
close(fd_w);
munmap(file_buf_r,file_len);
unlink(destination);
return 1;
}
file_buf_w = (char *) mmap(NULL, file_len, PROT_WRITE, MAP_SHARED, fd_w,
SEEK_SET);
if (file_buf_w == MAP_FAILED) {
close(fd_w);
munmap(file_buf_r, file_len);
unlink(destination);
return 1;
}
close(fd_w);
if (NULL == memcpy(file_buf_w, file_buf_r, file_len)) {
munmap(file_buf_r, file_len);
munmap(file_buf_w, file_len);
unlink(destination);
return 1;
}
if (msync(file_buf_w, file_len, MS_SYNC) < 0) {
munmap(file_buf_r, file_len);
munmap(file_buf_w, file_len);
unlink(destination);
return 1;
}
munmap(file_buf_r, file_len);
munmap(file_buf_w, file_len);
return 0;
}
接着贴上我使用read和write复制文件的函数代码:
static int copyfile(const char * source,const char * destination,int mode)
{
int srcfd,desfd;
int exit_status;
off_t filelen;
ssize_t nwrite,n;
exit_status = 0;
srcfd = -1;
desfd = -1;
char * buf[BUFFSIZE];
if (NULL == source || NULL == destination) {
exit_status = 1;
goto exit_program;
}
if (0 == mode) {
mode = 0660;
}
if (access(source,F_OK) < 0) {
exit_status = 1;
goto exit_program;
}
if ( (srcfd = open(source,O_RDONLY)) < 0 ) {
exit_status = 1;
goto exit_program;
}
if (creat(destination,mode) < 0) {
exit_status = 1;
goto exit_program;
}
if ((desfd = open(destination,O_WRONLY,O_APPEND)) < 0) {
exit_status = 1;
goto exit_program;
}
filelen = lseek(srcfd,0,SEEK_END);
lseek(desfd,0,SEEK_SET);
nwrite = 0;
while (nwrite < filelen) {
n = pread(srcfd,buf,BUFFSIZE,nwrite);
if (n < 0) {
exit_status = 1;
goto exit_program;
}
n = write(desfd,buf,n);
if (n < 0) {
exit_status = 1;
goto exit_program;
}
nwrite += n;
}
exit_status = 0;
exit_program:
if (srcfd >= 0) {
close(srcfd);
}
if (desfd >= 0) {
if (1 == exit_status) {
unlink(destination);
}
close(desfd);
}
return exit_status;
}
看这两个函数的代码数量相差不大,但是性能却有所差异
原本我以为使用mmap会使得复制更快,但是结果却是read和write组合复制文件更快些
经过我多次测试,测试复制100个图片文件
使用mmap的函数使用大概2.5s
而使用read和write的函数使用大概2.3s
虽然只有0.2s的差距,但是如果文件数量一大,那么这个差距就显示出来了
我这里并不是说mmap没有用处,本来mmap的定位都是用于进程间共享内存的
所以如果对于复制文件这样没有共享内存的操作,mmap失去了优势,反而可能成为劣势,不如read和write
但是如果是两个进程间通信,如果用read和write对管道(FIFO等)进行数据读写,那么效率肯定是不如直接使用mmap高效