2016-02-29 161 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。

謝謝。