内存映射文件创建方式的部分疑问

zixingcheng_ 2015-01-27 06:04:09
最近在用MemoryMappedFile 进行大文件操作研究,发现其CreateOrOpen、CreateFromFile两个创建方法出来的存取效率差别好大,测试源数据80M的Ascii栅格文件(5000*4000大小),读入后扩展了一倍的数据存储位置用于存储计算数据(直接理解为数据量翻倍),存贮的MemoryMappedFile 文件为320m。

测试结果:CreateOrOpen,创建耗时4s内,操作8s内,
CreateFromFile,读取耗时ms级忽略,操作20s左右

问题:1.有没有对MemoryMappedFile 有研究的,能说明下两个方法的主要区别?或者是效率差异的原因?

2.CreateFromFile方法有没办法优化存取速度?个人还是想优先使用该方法,毕竟超大文件可以直接打开,而不用每次创建初始。


相关创建的源码如下:

protected MemoryMappedFile m_objMemoryMapped

/// <summary>创建内存映射文件
/// </summary>
/// <param name="strMapName">内存映射文件名称</param>
/// <param name="objAccess">内存映射文件允许的访问类型</param>
/// <returns></returns>
public virtual bool Create(string strMapName, MemoryMappedFileAccess objAccess)
{
try
{
//创建内存映射文件
m_strMapName = strMapName;
if (p_MapPath + "" == "")
{
m_objMemoryMapped = MemoryMappedFile.CreateOrOpen(strMapName, m_nCapacity2, objAccess);
}
else
{
//判断是否存在
m_bIsExist = clsFile.IsExist_File(p_MapPath);

//创建
if (m_bIsExist)
{
m_objMemoryMapped = MemoryMappedFile.CreateFromFile(p_MapPath, FileMode.Open, strMapName, m_nCapacity2, objAccess);
}
else
{
m_objMemoryMapped = MemoryMappedFile.CreateFromFile(p_MapPath, FileMode.Create, strMapName, m_nCapacity2, objAccess);
}
}

//创建一个默认视图(避免视图为null)
m_objMapView = m_objMemoryMapped.CreateViewAccessor(0, m_nSize, objAccess);
return true;
}
catch
{
throw;
}
}
...全文
213 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
Forty2 2015-01-28
  • 打赏
  • 举报
回复
引用 4 楼 zixingcheng_ 的回复:
... 如果是操作系统的页面文件,这个也应该有IO的吧?如果有那跟CreateFromFile也没本质区别,不该有近一倍的效率差距。
如果完全只用内存就不是‘一倍的效率差距了’:) 如果是随机存储,内存和普通磁盘的差距可能是10万倍。即使是大块数据连续传输,差别可能到10倍。 另外,直接观察物理内存可能会有误导。原因是用CreateOrOpen来做3G+,并不意味着3G+都要放到内存里,预留内存地址(preserve)并不一定要占用(commit)物理内存。 其实从需求出发,你没有多少选择: 要操作具体的数据文件,那你只能用CreateFromFile。
zixingcheng_ 2015-01-28
  • 打赏
  • 举报
回复
引用 1 楼 Forty2 的回复:
CreateOrOpen和CreateFromFile的最大区别在于,前者没有具体的文件(支持载体可以是内存,也可以是操作系统的页面文件),而后者要打开或保存一个具体的文件;前者不一定要磁盘读取和回写,而后者要读取文件和写回磁盘。由于磁盘IO比内存IO慢了太多,因此你观察到两个的速度区别。

因为你的需求要读取和保存结果,这决定你只能用CreateFromFile。
你也可以试试不用MemoryMappedFile ,因为320M的内存需求不算太高,可以在内存里面直接操作数据,最后写回结果。


介个,320m只是测试文件,常规可能会有几个G的,甚至十几个G,大型的模型计算,计算范围大,数据多,就是因为内存溢出才考虑使用这个。控制好视图,调整算法后,可以保证内存使用基本稳定(100m以内),目前只会这一种办法来实现。

你说CreateOrOpen这个使用内存,感觉不是,之前有个测试是到3G+,是内存的话应该出问题的吧。
下面是前后资源使用情况,粗略的看基本没多大区别,应该不是直接使用内存。


如果是操作系统的页面文件,这个也应该有IO的吧?如果有那跟CreateFromFile也没本质区别,不该有近一倍的效率差距。
winnowc 2015-01-28
  • 打赏
  • 举报
回复
1. 这个1楼说了,CreateOrOpen不是用来操作文件的,它一般都是用来做进程间通信,所以并不一定真正写到磁盘。CreateFromFile才能用来操作文件。 2. 优化速度这个主要是可以优化下内存复制速度,比如http://ayende.com/blog/163138/memory-mapped-files-file-i-o-performance,使用API进行内存复制比WriteArray快了不少。不过这比FileStream的结果还慢一点点。 MMF 操作文件的速度优势主要体现在减少了内存复制,如果是c/c++,可以直接和结构体映射。但是对于托管环境,很可能还是需要在托管内存中创建对象,就抵消了它的优势。所以最好像给的链接里那样,对你的场景测试下三种实现的速度,看看哪个更好。
o_range 2015-01-28
  • 打赏
  • 举报
回复
看着分那么高,过来顶一下
zixingcheng_ 2015-01-28
  • 打赏
  • 举报
回复
目前也够用,也不是说只能CreateFromFile,留了接口,让调用的自己选吧,看能否容忍加载耗时,自己平衡加载、运算耗时来选择 ,数据量不同决定,哪种调用耗时最少。 还有更好的建议请留言,一天后结贴。
zixingcheng_ 2015-01-28
  • 打赏
  • 举报
回复
引用 5 楼 Forty2 的回复:
[quote=引用 4 楼 zixingcheng_ 的回复:] ... 如果是操作系统的页面文件,这个也应该有IO的吧?如果有那跟CreateFromFile也没本质区别,不该有近一倍的效率差距。
如果完全只用内存就不是‘一倍的效率差距了’:) 如果是随机存储,内存和普通磁盘的差距可能是10万倍。即使是大块数据连续传输,差别可能到10倍。 另外,直接观察物理内存可能会有误导。原因是用CreateOrOpen来做3G+,并不意味着3G+都要放到内存里,预留内存地址(preserve)并不一定要占用(commit)物理内存。 其实从需求出发,你没有多少选择: 要操作具体的数据文件,那你只能用CreateFromFile。[/quote] 嗯,我现在也基本只能用CreateFromFile了。 现在还是纠结CreateOrOpen,想弄明白他到底怎么存取的,具体到底存哪的,效率会高些的原因。 完全内存不现实,都说是映射内存文件了。 意思CreateOrOpen是用了预留内存地址和,或者说他缓存了比CreateFromFile更多的东西? 我纠结的核心看来是微软干嘛不能成一致的
引用 3 楼 github_22161131 的回复:
1. 这个1楼说了,CreateOrOpen不是用来操作文件的,它一般都是用来做进程间通信,所以并不一定真正写到磁盘。CreateFromFile才能用来操作文件。 2. 优化速度这个主要是可以优化下内存复制速度,比如http://ayende.com/blog/163138/memory-mapped-files-file-i-o-performance,使用API进行内存复制比WriteArray快了不少。不过这比FileStream的结果还慢一点点。 MMF 操作文件的速度优势主要体现在减少了内存复制,如果是c/c++,可以直接和结构体映射。但是对于托管环境,很可能还是需要在托管内存中创建对象,就抵消了它的优势。所以最好像给的链接里那样,对你的场景测试下三种实现的速度,看看哪个更好。
给的示例看了,也具体测试了,用内存拷贝的确快了,不过写入还是低,总体提升50%吧。 不过还是有问题,用内存拷贝视图里的东西时,数据乱了。好像数据在视图内对应地址不是连续的!数据乱的还没规律可言,偏移应该是没问题的,之前直接写就对的,得到的栅格结果,可以发现部分区是正确的,只是会有不规则的位置移动,只有极少部分数据位置没变,完全找不到规律。 准备放弃了。效率低点就低点吧
Forty2 2015-01-28
  • 打赏
  • 举报
回复
CreateOrOpen和CreateFromFile的最大区别在于,前者没有具体的文件(支持载体可以是内存,也可以是操作系统的页面文件),而后者要打开或保存一个具体的文件;前者不一定要磁盘读取和回写,而后者要读取文件和写回磁盘。由于磁盘IO比内存IO慢了太多,因此你观察到两个的速度区别。 因为你的需求要读取和保存结果,这决定你只能用CreateFromFile。 你也可以试试不用MemoryMappedFile ,因为320M的内存需求不算太高,可以在内存里面直接操作数据,最后写回结果。

110,533

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

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