В следующем случае, какой из них лучше? fread() или mmap()?
Я хочу прочитать два файла через процесс, первый файл около 2G, второй файл около 20M. Они выглядят так:
1 1217907
1 1217908
1 1517737
1 2
1 3
1 4
1 5
Теперь я планирую прочитать весь файл в память, а затем использовать strtok_r()
чтобы получить значение каждого числа и сохранить их в массиве структуры данных. 4 процесса могут читать эти два файла на одном компьютере практически одновременно. Компьютер 64-битный, физическая память может быть 4G или даже меньше. У меня вопрос, какой метод является более эффективным? fread()
или же mmap()
?
Вот ключевая часть моей программы чтения всего файла (поскольку кто-то хочет его увидеть, но я не знаю, связано ли это с моим вопросом):
typedef struct My_Edge
{
int first;
int second;
}Edge;
Edge *myEdge;
int Read_Whole_File()
{
fseek(wholeFile, 0, SEEK_END);
long int fileSize=ftell(wholeFile);
char *buffer=malloc(sizeof(char)*fileSize+1);
fseek(wholeFile, 0, SEEK_SET);
fread(buffer, 1, fileSize, wholeFile);
char *string_first;
char *string_second;
char *save_ptr;
int temp_first;
int temp_second;
string_first = strtok_r(buffer, " \t\n", &save_ptr);
int i=0;
int temp_edge_num;
Edge *temp_edge;
while (string_first != NULL)
{
temp_first = atoi(string_first);
string_second = strtok_r(NULL," \t\n",&save_ptr);
temp_second = atoi(string_second);
if(i>=my_edge_num)
{
temp_edge_num = i + EDGE_NUM_ADJUST;
temp_edge = realloc(myEdge, sizeof(Edge)*temp_edge_num);
if(temp_edge)
{
myEdge = temp_edge;
}
my_edge_num = temp_edge_num;
}
if((p_id[temp_first]==*partitionID)||(p_id[temp_second]==*partitionID))
{
myEdge[i].first=temp_first;
myEdge[i].second=temp_second;
i++;
}
string_first = strtok_r(NULL, " \t\n", &save_ptr);
}
return 0;
}
Сейчас я пытаюсь использовать mmap()
, но у меня есть EXC_BAD_ACCESS, когда я использую strtok_r()
ТП обработать переменную, которая обрабатывается mmap()
:
символ * буфер;
struct stat fileStat;
fstat(wholeFile, &fileStat);
buffer = mmap(NULL, fileStat.st_size, PROT_READ, MAP_SHARED, wholeFile, 0);
char *string_first;
char *string_second;
char *save_ptr;
int temp_first;
int temp_second;
string_first = strtok_r(buffer, " \t\n", &save_ptr);//EXC_BAD_ACCESS here, the content of buffer is correct.
1 ответ
У меня вопрос, какой метод является более эффективным? fread() или mmap()?
Прежде всего, давайте посмотрим, как fread и mmap работают на Linux:fread
:
Допустим, мы работаем с файловой системой ext4 (без шифрования),
fread использует некоторый внутренний буфер и, если в нем нет данных,
это вызывает read
, read
выполнить "системный вызов" и через некоторое время мы переходим к:
fs / read_write.c:: vfs_read и после дополнительной работы мы достигаем mm/filemap.c::generic_file_read_iter
И в этой функции мы заполняем кэш страницы inode и читаем данные кеша этой страницы.
Таким образом, мы делаем то же самое, что и "mmap".
Разница что то в fread
если мы не работаем напрямую со страницами, мы просто копируем часть данных из кэша страниц inode ядра в буфер пространства пользователя,
в mmap
у нас есть кеш страниц прямо в памяти программы. Плюс в fread
когда нет страницы в "кеше страницы inode", мы просто читаем ее, но в mmap
что вызывает "ошибку страницы", и только после этого мы ее читаем.
Оба варианта используют стратегию "прочитай страницы впереди". Возможная разница может быть в политике "кеша", мы можем контролировать ее в случае "mmap" с madvise
и флаги mmap
,
Поэтому я полагаю, что ответ "они почти одинаковы по скорости в последовательном чтении, как у вас".