2016-02-29 159 views
1

我目前在一个软件中使用两个映射文件(第一个是1.9 GBytes,第二个是600 MBytes)的共享内存。
我正在使用从第一个文件读取数据,处理数据并将结果写入第二个文件的进程。
在使用memcpy函数读取或写入映射视图时,我注意到有时会出现强烈的延迟(原因不在我的知识范围内)。
Windows共享内存访问时间较慢

映射文件被创建这样:

m_hFile = ::CreateFileW(SensorFileName, 
         GENERIC_READ | GENERIC_WRITE, 
         0, 
         NULL, 
         CREATE_ALWAYS, 
         FILE_ATTRIBUTE_NORMAL, 
         NULL); 

m_hMappedFile = CreateFileMapping(m_hFile, 
            NULL, 
            PAGE_READWRITE, 
            dwFileMapSizeHigh, 
            dwFileMapSizeLow, 
            NULL); 

和内存映射完成这样:

m_lpMapView = MapViewOfFile(m_hMappedFile, 
          FILE_MAP_ALL_ACCESS, 
          dwOffsetHigh, 
          dwOffsetLow, 
          m_i64ViewSize); 

的dwOffsetHigh/dwOffsetLow是 “匹配” 从系统中信息的粒度。

该进程正在读取大约300KB * N次,将其存储在缓冲区中,然后将300KB * N次的前一缓冲区的处理内容写入第二个文件。
我有两个不同的内存视图(使用MapViewOfFile函数创建/移动),大小为10 MBytes作为默认大小。
对于内存视图大小,我测试了10kBytes,100kB,1MB,10MB和100MB。
统计上没有区别,80%的时间读取过程如下所述(〜200ms),但写入过程非常慢。

通常情况下:
1 /读取在〜200ms内完成。
2 /过程在2.9秒内完成。
3 /写作在200ms内完成。

我可以看到,80%的时间,无论是阅读还是写作(在最坏的情况下,两者都很慢)将需要2到10秒。

例如:对于写作,我使用下面的代码

for (unsigned int i = 0 ; i < N ; i++) // N = 500~3k 
{ 
    // Check the position of the memory view for ponderation 
    if (###) 
     MoveView(iOffset); 

    if (m_lpMapView) 
    { 
     memcpy((BYTE*)m_lpMapView + iOffset, pANNHeader, uiANNStatus); 
     // uiSize = ~300 kBytes 
     memcpy((BYTE*)m_lpMapView + iTemp, pLine[i], uiSize); 
    } 
    else 
     return uiANNStatus; 
} 

使用GetTickCount函数后要找准其中的延迟,我看到的是,第二的memcpy调用总是一个走的大部分时间。
因此,到目前为止,在使用这些共享内存的最差时间,我看到N(对于测试,我使用N = 500)调用memcpy,其中10秒
我做了一个临时软件,它执行相同数量的memcpy调用,数据量相同,但无法看到问题。

对于测试中,我使用以下条件,它们都显示出相同的延迟:
1/I可以看到这在各种计算机上,从窗口7 32或64位至10窗户
2 /使用主线程或多线程(最多8个用于同步目的的关键部分)用于读/写。
SATA或SSD上的3/OS,物理上位于SATA或SSD硬盘上的软件内存映射文件,如果在外部硬盘上,则通过USB1,USB2或USB3完成测试。

我很好奇地问你,我认为我的错误是memcpy变慢。

此致敬礼。

+1

这对存储器映射文件来说是正常的。在某些情况下,它需要将数据物理提交到磁盘 - 并且您的磁盘IO绑定。 – SergeyA

+0

您可能想要针对代码更改进行配置文件,而您正在缓存数据而不使用内存映射文件。改变缓冲区的大小而不是输入块大小以获得性能。 –

+0

在MSDN网站上搜索可锁定内存的API,以防止操作系统将其与硬盘进行交换。 –

回答

0

我发现了一个适用于我的解决方案,但对其他人来说可能不是这样。
按照Thomas Matthews的评论,我检查了MSDN并发现了两个有趣的函数FlushViewOfFile和FlushFileBuffers(但是找不到有关锁定内存的任何有趣内容)。
在for循环强制更新映射文件后调用两者。
我没有更多的“随机”延迟,但而不是预期的200毫秒,我有平均400毫秒这足够我的应用程序。

经过一些测试后,我看到,经常调用这些操作会导致硬盘访问过多,并且会使延迟变得更糟(每个循环都需要10秒钟),所以应该小心使用flush。

谢谢。