Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
File 为什么(ftruncate+;mmap+;memcpy)比(write)快?_File_Unix_Optimization_Mmap - Fatal编程技术网

File 为什么(ftruncate+;mmap+;memcpy)比(write)快?

File 为什么(ftruncate+;mmap+;memcpy)比(write)快?,file,unix,optimization,mmap,File,Unix,Optimization,Mmap,我发现了一种不同的数据写入方法,它比普通的unixwrite函数更快 首先,ftruncate将文件运行到我们需要的长度,然后mmap此文件块,最后,使用memcpy刷新文件内容。我将给出下面的示例代码 正如我所知,mmap可以将文件加载到进程地址空间,通过忽略页面缓存来加快加载速度。但是,我不知道为什么它能加快写作速度 是我写了一个错误的测试用例,还是它可能是一种opti技巧 这是测试代码。有些是用ObjC写的,但没关系WCTTicker只是一个使用gettimeofday的统计类 //fin

我发现了一种不同的数据写入方法,它比普通的unix
write
函数更快

首先,
ftruncate
将文件运行到我们需要的长度,然后
mmap
此文件块,最后,使用
memcpy
刷新文件内容。我将给出下面的示例代码

正如我所知,mmap可以将文件加载到进程地址空间,通过忽略页面缓存来加快加载速度。但是,我不知道为什么它能加快写作速度

是我写了一个错误的测试用例,还是它可能是一种opti技巧

这是测试代码。有些是用ObjC写的,但没关系
WCTTicker
只是一个使用
gettimeofday
的统计类

//find a dir to test
NSString* document = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString* dir = [document stringByAppendingPathComponent:@"testDir"];

//remove all existing test
if ([[NSFileManager defaultManager] fileExistsAtPath:dir]) {
    if (![[NSFileManager defaultManager] removeItemAtPath:dir error:nil]) {
        NSLog(@"fail to remove dir");
        return;
    }
}
//create dir to test
if (![[NSFileManager defaultManager] createDirectoryAtPath:dir withIntermediateDirectories:YES attributes:nil error:nil]) {
    NSLog(@"fail to create dir");
}

//pre-alloc memory
const int length = 10000000;
const int count = 100;
char* mem = (char*)malloc(length);
memset(mem, 'T', length);

{
    //start testing mmap
    // ftruncate && mmap(private) &&memcpy
    NSString* mmapFileFormat = [dir stringByAppendingPathComponent:@"privateMmapFile%d"];
    [WCTTicker tick];
    for (int i = 0; i < count; i++) {
        NSString* path = [[NSString alloc] initWithFormat:mmapFileFormat, i];
        int fd = open(path.UTF8String, O_CREAT | O_RDWR, S_IRWXG | S_IRWXU | S_IRWXO);
        if (fd<0) {
            NSLog(@"fail to open");
        }
        int rc = ftruncate(fd, length);
        if (rc<0) {
            NSLog(@"fail to truncate");
        }
        char* map = (char*)mmap(NULL, length, PROT_WRITE | PROT_READ, MAP_PRIVATE, fd, 0);
        if (!map) {
            NSLog(@"fail to mmap");
        }
        memcpy(map, mem, length);
        close(fd);
    }
    [WCTTicker stop];
}

{
    //start testing write
    // normal write
    NSString* writeFileFormat = [dir stringByAppendingPathComponent:@"writeFile%d"];
    [WCTTicker tick];
    for (int i = 0; i < count; i++) {
        NSString* path = [[NSString alloc] initWithFormat:writeFileFormat, i];
        int fd = open(path.UTF8String, O_CREAT | O_RDWR, S_IRWXG | S_IRWXU | S_IRWXO);
        if (fd<0) {
            NSLog(@"fail to open");
        }
        int written = (int)write(fd, mem, length);
        if (written!=length) {
            NSLog(@"fail to write");
        }
        close(fd);
    }
    [WCTTicker stop];
}

{
    //start testing mmap
    // ftruncate && mmap(shared) &&memcpy
    NSString* mmapFileFormat = [dir stringByAppendingPathComponent:@"sharedMmapFile%d"];
    [WCTTicker tick];
    for (int i = 0; i < count; i++) {
        NSString* path = [[NSString alloc] initWithFormat:mmapFileFormat, i];
        int fd = open(path.UTF8String, O_CREAT | O_RDWR, S_IRWXG | S_IRWXU | S_IRWXO);
        if (fd<0) {
            NSLog(@"fail to open");
        }
        int rc = ftruncate(fd, length);
        if (rc<0) {
            NSLog(@"fail to truncate");
        }
        char* map = (char*)mmap(NULL, length, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
        if (!map) {
            NSLog(@"fail to mmap");
        }
        memcpy(map, mem, length);
        close(fd);
    }
    [WCTTicker stop];
}
您有
mmap()
但没有相应的
munmap()

mmap
手册页(linux)

映射共享此映射。映射的更新可见 到映射此文件的其他进程,并执行到 基础文件。在msync(2)之前,文件可能不会实际更新 或者调用munmap()

也许您应该再次运行测试,以便调用
munmap

char* map = (char*)mmap(NULL, length, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
if (!map) {
   NSLog(@"fail to mmap");
}
memcpy(map, mem, length);
munmap(map, length);
close(fd);

即使添加了munmap(或msync),我认为这至少对于大数据传输来说应该更快,因为write()会导致复制操作,而mmap和对映射的访问则不会。write

write
更慢,因为它与操作系统和libc I/O缓冲一起工作,而mmap几乎直接进入磁盘。关键是文件创建/截断等的开销比
写入的I/O缓冲要大多少。这取决于你的成败。@GMichael write是纯操作系统,不是libc缓冲,只是操作系统缓冲。@Jean BaptisteYunès这取决于实现。即使您是正确的,仍然存在操作系统缓冲。
write
使用内部操作系统缓冲,而
mmap
使用虚拟内存。使用
mmap
您可以写入内存(通常这是非常快的),然后
unmap
您的进程虚拟内存刚刚从它的空间中释放出来,但是内核得到它并花时间代表进程刷新磁盘上的数据。@GMichael缓冲是一种加速I/O而不是减慢I/O速度的工具,因此,对于为什么O/S缓冲在这里失败,它缺乏一些很好的解释。而且,没有写操作是纯操作系统(至少在Unix系统上是如此)…确切地说。OP只测量
memcpy()
mmap()
不会绕过页面缓存。读什么
char* map = (char*)mmap(NULL, length, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
if (!map) {
   NSLog(@"fail to mmap");
}
memcpy(map, mem, length);
munmap(map, length);
close(fd);