mmap()的效率咋就这么低呢?

duanbeibei 2007-07-25 12:25:25
设计到大文件的编程,不可能一次将文件内容全部读到内存,就用了mmap()函数,将文件映射到内存,网上很多人说mmap速度要快一些,可我的测试结果是mmap的读取速度比正常的read慢的多,下面是我的测试代码:
//--------------------------------------------------------------
//mmap.c
int main(int argc, char **argv)
{
int fd = -1;
struct stat f_stat;
unsigned char *start = NULL;
unsigned char *buf = NULL;

if (argc != 2)
return -1;

if ((fd = open(argv[1], O_RDONLY)) == -1)
return -1;
if (fstat(fd, &f_stat))
return -1;

if ((start = mmap(start, f_stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == NULL)
return -1;

time_t time1,time2;
int len = 1024 * 1024 * 10;
buf = (unsigned char *)malloc(len);
int i;

time1 = time(NULL);
for (i = 0; i < f_stat.st_size/len; i++)
{
memcpy(buf, start + i * len, len);
}
time2 = time(NULL);
free(buf);

printf("consume time:%d\n", time2 - time1);

if (munmap(start, f_stat.st_size))
return -1;
close(fd);
}

//------------------------------------------------------------------
//fread.c
int main(int argc, char **argv)
{
int fd = -1;
struct stat f_stat;
unsigned char *start = NULL;
unsigned char *buf = NULL;

if (argc != 2)
return -1;

if ((fd = open(argv[1], O_RDONLY)) == -1)
return -1;
if (fstat(fd, &f_stat))
return -1;


time_t time1,time2;
int len = 1024 * 1024 * 10;
buf = (unsigned char *)malloc(len);
int i;

time1 = time(NULL);
for (i = 0; i < f_stat.st_size/len; i++)
{
read(fd, buf, len);
}
time2 = time(NULL);
free(buf);

printf("consume time:%d\n", time2 - time1);
close(fd);
}
//-------------------------------------------------------------
读取的文件大小为740MB,mmap用时137秒,而正常的文件读写仅用20秒,敬请高手解答!!!
...全文
2744 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
hfutxrg 2012-08-19
  • 打赏
  • 举报
回复
这样测根本不对。哪有人一下子读740M的,肯定要用buffer啊。你加了buffer试试看,肯定比mmap要快很对。而且测read()时,也不应该加memcpy().
duanbeibei 2007-07-25
  • 打赏
  • 举报
回复
//-------------------------
char *tmp=(unsigned char *)malloc(len);
for (i = 0; i < f_stat.st_size/len; i++)
{
read(fd, buf, len);
memcpy(tmp,buf,len);
}
free(tmp);
//--------------------------
用这个方法重新测试了一下,结果还是一样的,这里的memcpy仅仅消耗了5秒时间,据我了解,mmap采用的是虚拟内存技术,虽然获得了映射地址,但要从“虚内存中”读数据的话要不停的进行页面置换,才能真正将数据读到内存,因而是很耗时的
现在的测试结果是:read将文件读到内存 + memcpy到另一内存 〈 mmap + memcpy到另一内存
就是说从mmap的到的内存地址中取数据非常慢
cceczjxy 2007-07-25
  • 打赏
  • 举报
回复
映射成功后,你就可以认为已经读到内存了,你后边又memcpy,就等于把数据又都拷贝了一遍.
如果想测试的话,你可以,
char *tmp=(unsigned char *)malloc(len);
for (i = 0; i < f_stat.st_size/len; i++)
{
read(fd, buf, len);
memcpy(tmp,buf,len);
}
free(tmp);
jufeng2309 2007-07-25
  • 打赏
  • 举报
回复
mmap并不分配空间, 只是将文件映射到调用进程的地址空间里, 然后就可以用memcpy等操作写文件...把一个文件的内容在内存里面做一个映像,内存比磁盘快些...

把相应的flag换成别的看看
start_fp = mmap(NULL,stat_data.st_size,PROT_READ,MAP_SHARED,fd,0 ))
dai_weitao 2007-07-25
  • 打赏
  • 举报
回复
你mmap之后还memcpy了一遍, 当然时间长了.
137秒就是memcpy的时间.
jufeng2309 2007-07-25
  • 打赏
  • 举报
回复
将上面改成这样试试。。。

if( ( start_fp = mmap(NULL,stat_data.st_size,PROT_READ,MAP_SHARED,fd,0 )) == (void *)-1)
{
printf("error\n");
}
duanbeibei 2007-07-25
  • 打赏
  • 举报
回复
非常感谢cceczjxy!!!
之前是在虚拟机上测试的,换了台真实的机器,性能果然上去了,按照cceczjxy的方法重新测试了一道,mmap共用时18秒,传统读取时read()用时27秒,memcpy()时又用掉40秒!!!!
cceczjxy 2007-07-25
  • 打赏
  • 举报
回复
mmap只能使用先存的文件大小,没法增加或缩短文件长度.
dai_weitao 2007-07-25
  • 打赏
  • 举报
回复
我刚才写了段程序试了, 在原映射上修改保持原长度可以, 但如果要是增加或缩短文件长度就不能实现了.
请问楼主在这方面怎么实现的?
cceczjxy 2007-07-25
  • 打赏
  • 举报
回复
刚才给你贴错了,没贴全
我在上边给使len=f_stat.st_size了.

你可以这样试一下.
再补充一下:映射实际上就是为映射的空间建立页面表项,但此时页面并没有在内存中分配空间.
只有到使用的那个地址的空间时,才给此页面分配空间.使用映射的空间逐个块逐个块的使用,就学要,为每个
页面项在内存中都要分配空间.读取数据实际上是很快,主要是可能由于你实际的内存太小,内存空间不足,在使用过程中,刚分配的内存空间又要被交换到磁盘上.大部分时间都被用在这样的交换上了.

而使用read读取数据时,由于一次读取的数据块少,故不需要这样的交换.

你使用下边的程序测试一下就知道如果一次把整个文件一次都读取进来进行处理是多么的慢了.


实际上mmap的优点主要在为用户程序随机的访问,操作,文件提供了一个方便的操作方法.
其次就是为不同进程共享大批量数据提供高效的手段.

比如说数据库对其数据的访问,如果用read,fseek来随机访问的话,那效率和并发性就很成问题了.



#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
int fd = -1;
struct stat f_stat;
unsigned char *start = NULL;
unsigned char *buf = NULL;

if (argc != 2)
return -1;

if ((fd = open(argv[1], O_RDONLY)) == -1)
return -1;
if (fstat(fd, &f_stat))
return -1;


time_t time1,time2;
int len = 1000*1000;
char *tmp=(unsigned char *)malloc(len);
buf = (unsigned char *)malloc(f_stat.st_size);
int i;
time1 = time(NULL);
read(fd,buf,f_stat.st_size);
for (i = 0; i < f_stat.st_size/len; i++)
{
memcpy(tmp,buf+len*i,len);
}
time2 = time(NULL);
free(buf);
free(tmp);
printf("consume time:%d\n", time2 - time1);
close(fd);
}
dai_weitao 2007-07-25
  • 打赏
  • 举报
回复
如果认为映射成功后没有读到内存, 还需要用memcpy的话.
那么你可以在映射成功后printf("%s", start);一下试试.

23,121

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 应用程序开发区
社区管理员
  • 应用程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧