在进程之间处理大型文件的mmap和fread

时间:2015-12-17 13:44:03

标签: c linux multiprocessing mmap fread

我有两个过程: 进程A将大文件(~170 GB - 内容不断变化)映射到内存中,使用标记 MAP_NONBLOCK MAP_SHARED 进行编写:

MyDataType *myDataType; = (MyDataType*)mmap(NULL, sizeof(MyDataType), PROT_WRITE, MAP_NONBLOCK | MAP_SHARED , fileDescriptor, 0);

每秒我都会调用msync:

msync((void *)myDataType, sizeof(MyDataType), MS_ASYNC); 

此部分正常。

当进程B尝试从进程A映射到的同一文件中读取时,会出现问题,进程A没有响应约20秒。 进程B尝试使用fread()fseek()小块(每次约4个字节)从文件中读取1000次。 该过程正在阅读的大部分内容彼此接近。

这个问题的原因是什么?它与页面分配有关吗?我该如何解决?

顺便说一句,当我在流程B中使用mmap()而不是简单fread()时,会出现同样的问题。

3 个答案:

答案 0 :(得分:4)

msync()可能是问题所在。它强制系统写入磁盘,在写入狂热中阻止内核。 通常在Linux上(在Solaris BTW上它是相同的),经常使用msync()是个坏主意。没有必要调用msync()来实现内存映射和read()/write() I / O操作之间的数据同步,这是一种来自过时的HOWTO的误解。实际上,mmap()仅使文件系统缓存"可见"一个过程。这意味着内存块阻止进程更改仍在内核控制之下。即使您的进程崩溃,更改也会最终落在磁盘上。其他进程仍然可以由相同的缓冲区提供服务。

这里有关于这个问题的另一个答案mmap, msync and linux process termination 有趣的部分是关于realworldtech讨论的链接,其中Linus Torvalds自己解释了缓冲区缓存和内存映射的工作原理。

PS:fseek()/fread()对也可能更好地被pread()取代。 1系统调用始终优于2.同时fseek()/fread()读取总是4K并在缓冲区中复制,因此如果您有几个没有fseek()的小读取,它将从其本地缓冲区读取并可能错过更新过程A.

答案 1 :(得分:0)

这听起来你正在遭受IO-Starvation,这与你选择的方法(mmap或fread)无关。你必须改进你的(预)缓存策略和/或尝试另一个IO调度程序(cfq是默认的,也许截止日期为你提供更好的整体结果)

您可以通过写入/ sys:

来更改调度程序
SELECT a.country_name, s.state_name, c.city_id,
LEAST (c.next_1, c.next_2, c.next_3) AS next_visit,
MAX(v.visit_time) AS last_visit
FROM city c
INNER JOIN country a ON a.id = c.country
INNER JOIN state s ON s.id = c.state 
INNER JOIN visit_log v ON CONCAT(c.country, c.state, c.city_id) = CONCAT(v.country, v.state, v.city_id)
GROUP BY CONCAT(v.country, v.state, v.city_id)
ORDER BY a.id ASC, s.id ASC, c.city_id

答案 2 :(得分:0)

也许你应该尝试分析甚至使用strace来确定进程花费时间的位置。 20秒在msync()中被io解释似乎非常漫长。

当你说A没有回应时,你究竟是什么意思?