POSIX环境提供至少两种访问文件的方法.有标准的系统调用open(),read(),write(),和朋友,但也有使用的选项mmap(),将文件映射到虚拟内存.
何时优先使用一个而不是另一个?它们各自的优势是什么,包括两个接口?
我正在开发一个程序,该程序将处理可能大小为100GB或更大的文件.这些文件包含一组可变长度记录.我已经启动并运行了第一个实现,现在我正在寻求提高性能,特别是在输入文件被多次扫描时更有效地进行I/O.
mmap()通过C++的fstream库使用和读取块有经验吗?我想做的是从磁盘读取大块到缓冲区,从缓冲区处理完整记录,然后阅读更多.
该mmap()代码可能会变得非常凌乱,因为mmap"d块需要躺在页大小的边界(我的理解)和记录可能潜在般划过页面边界.使用fstreams,我可以寻找记录的开头并再次开始阅读,因为我们不仅限于阅读位于页面大小边界的块.
如何在不实际编写完整实现的情况下决定这两个选项?任何经验法则(例如,mmap()快2倍)或简单测试?
我正在用这个把我的头撞到墙上。
在我的项目中,使用mmap映射(/proc/self/maps)分配内存时,尽管我只请求了可读内存,但它仍是一个可读且可执行的区域。
在研究了strace(看起来不错)和其他调试之后,我能够确定似乎唯一可以避免这个奇怪问题的东西:从项目中删除程序集文件,只保留纯C。(什么?!)
所以这是我一个奇怪的例子,我正在使用Ubunbtu 19.04和默认的gcc。
如果使用ASM文件(为空)编译目标可执行文件,则将mmap返回一个可读和可执行区域,如果构建时没有该区域,则它将正常运行。请参阅/proc/self/maps示例中已嵌入的输出。
example.c
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
int main()
{
void* p;
p = mmap(NULL, 8192,PROT_READ,MAP_ANONYMOUS|MAP_PRIVATE,-1,0);
{
FILE *f;
char line[512], s_search[17];
snprintf(s_search,16,"%lx",(long)p);
f = fopen("/proc/self/maps","r");
while (fgets(line,512,f))
{
if (strstr(line,s_search)) fputs(line,stderr);
}
fclose(f);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
example.s:是一个空文件!
产出
附带ASM版本
VirtualBox:~/mechanics/build$ gcc example.c example.s -o example && ./example
7f78d6e08000-7f78d6e0a000 r-xp 00000000 00:00 0
Run Code Online (Sandbox Code Playgroud)
没有ASM随附的版本
VirtualBox:~/mechanics/build$ gcc example.c -o example && ./example
7f1569296000-7f1569298000 …Run Code Online (Sandbox Code Playgroud) 我正在尝试使用以下代码(test.c)"mmap"二进制文件(~8Gb).
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
int main(int argc, char *argv[])
{
const char *memblock;
int fd;
struct stat sb;
fd = open(argv[1], O_RDONLY);
fstat(fd, &sb);
printf("Size: %lu\n", (uint64_t)sb.st_size);
memblock = mmap(NULL, sb.st_size, PROT_WRITE, MAP_PRIVATE, fd, 0);
if (memblock == MAP_FAILED) handle_error("mmap");
for(uint64_t i = 0; i < 10; i++)
{
printf("[%lu]=%X ", i, memblock[i]);
}
printf("\n");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
test.c是使用 …
我有一个长期存在的应用程序,频繁的内存分配 - 释放.任何malloc实现都会将释放的内存返回给系统吗?
在这方面,什么是以下行为:
如果我有一个应用程序,其白天和夜晚的内存消耗可能非常不同(例如),我可以强制任何malloc将系统释放的内存吗?
如果没有这样的返回,释放的内存将被多次换出,但这样的内存只包含垃圾.
我有一个程序可以映射相当多的(100个)大小的文件,每个文件10-100MB.我需要它们全部同时映射.
目前我打电话open,然后mmap在程序,随后开始munmap和close结尾.
通常我必须ulimit -n在运行程序之前调整打开的文件限制.
问题是我实际上需要保持文件打开,或者我可以在完成后open mmap close进行一些大数据处理munmap.
的手册页mmap似乎并不非常清楚,我在这一个.
php artisan migrate,出现以下错误:
[PDOException]
SQLSTATE[HY000] [2002] No such file or directory
Run Code Online (Sandbox Code Playgroud)注意:php -v是5.5,mysql -v是终端的5.5这是我的config/database.php的一部分
'mysql' => array(
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'essays',
'username' => 'root',
'password' => 'root',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
Run Code Online (Sandbox Code Playgroud)
我尝试用127.0.0.1替换localhost但没有用.请帮忙..
编辑: 我在php.ini中添加了这三行
mysql.default_socket = /var/run/mysqld/mysqld.sock
mysqli.default_socket = /var/run/mysqld/mysqld.sock
pdo_mysql.default_socket = /var/run/mysqld/mysqld.sock
Run Code Online (Sandbox Code Playgroud)
我还添加了这个符号链接:
sudo mkdir /var/mysql
cd /var/mysql && sudo ln -s /Applications/XAMPP/xamppfiles/var/mysql/mysql.sock
Run Code Online (Sandbox Code Playgroud)
但那并没有解决.我也是从混帐拉一个全新的laravel项目后遇到同样的错误composer install,然后php artisan migrate
[PDOException]
SQLSTATE[HY000] [2002] No such file …Run Code Online (Sandbox Code Playgroud) [编辑:此问题仅适用于32位系统.如果你的计算机,你的操作系统和你的python实现是64位的,那么mmap-ing巨大的文件可以正常工作并且非常高效.
我正在编写一个模块,其中包括允许按位读取文件访问.这些文件可能很大(数百GB),所以我编写了一个简单的类,让我像处理字符串一样处理文件并隐藏所有的搜索和阅读.
当我写我的包装类时,我不知道mmap模块.在阅读mmap的文档时,我认为"很棒 - 这正是我所需要的,我将取出我的代码并用mmap替换它.它可能效率更高,删除代码总是好的."
问题是mmap不适用于大文件!这对我来说非常令人惊讶,因为我认为它可能是最明显的应用程序.如果文件超过几千兆字节,那么我得到一个EnvironmentError: [Errno 12] Cannot allocate memory.这只发生在32位Python构建中,所以它似乎耗尽了地址空间,但我找不到任何关于此的文档.
我的代码就是
f = open('somelargefile', 'rb')
map = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
Run Code Online (Sandbox Code Playgroud)
所以我的问题是我错过了一些明显的东西吗?有没有办法让mmap可以在大文件上移植,或者我应该回到我天真的文件包装器?
更新:似乎有一种感觉,Python mmap应该具有与POSIX mmap相同的限制.为了更好地表达我的挫败感,这是一个简单的类,它具有mmap的一小部分功能.
import os
class Mmap(object):
def __init__(self, f):
"""Initialise with a file object."""
self.source = f
def __getitem__(self, key):
try:
# A slice
self.source.seek(key.start, os.SEEK_SET)
return self.source.read(key.stop - key.start)
except AttributeError:
# single element
self.source.seek(key, os.SEEK_SET)
return self.source.read(1)
Run Code Online (Sandbox Code Playgroud)
它是只读的,并没有做任何花哨的事情,但我可以像使用mmap一样:
map2 = Mmap(f)
print map2[0:10]
print map2[10000000000:10000000010]
Run Code Online (Sandbox Code Playgroud)
除了文件大小没有限制.真的不太难......
我有一个Linux应用程序,并行读取150-200个文件(4-10GB).每个文件依次以小的,可变大小的块读取,每个块通常小于2K.
我目前需要从文件集中保持超过200 MB/s的读取速率.磁盘处理这个很好.预计需要超过1 GB/s(目前不在磁盘范围内).
我们已经实现了两个不同的读取系统,它们都大量使用posix_advise:首先是mmaped读取,其中我们映射整个数据集并按需读取.第二个是基于read()/ seek()的系统.
两者都运行良好但仅适用于中等情况,该read()方法更好地管理我们的整体文件缓存并且可以很好地处理100 GB的文件,但是速率受限,mmap能够预先缓存数据使得持续数据速率超过200MB/s易于维护,但无法处理较大的总数据集大小.
所以我的问题来自于:
答:可以在Linux read()上posix_advise调用之外进一步优化类型文件i/o ,或者调整磁盘调度程序,VMM和posix_advise调用是否符合我们的预期?
B:有没有系统的方法让mmap更好地处理非常大的映射数据?
Mmap-vs-reading-blocks 与我正在工作的问题类似,并且提供了一个关于这个问题的良好起点,以及mmap-vs-read中的讨论.