2011-03-01 48 views
0

什麼是通過mmap-ed文件解析的最佳(最快)方法?它包含成對的數據(字符串int),但是我不能在它們之間留存空白/標籤/換行符的數量。解析mmap() - ed文件

+1

你是什麼意思的「解析」 - 什麼是存儲在文件中,你想做什麼?這個問題太模糊了,不能回答... – Nim 2011-03-01 11:33:11

+1

@Martin你知道strtok修改「源」,對吧?所以,如果你在你的mmap上使用它,你正在修改文件!你的文件是純文本還是二進制文件?你想要什麼類型的解析? – xanatos 2011-03-01 11:33:57

+0

投票結束。這是不可能的瞭解什麼是在這裏問 – 2011-03-01 11:35:03

回答

4

假設您已經mmaped中(而不是塊 - 因爲這將讓生活awefully複雜的)整個文件,我會做類似如下...

// Effectively this wraps the mmaped block 
std::istringstream str; 
str.rdbuf()->pubsetbuf(<pointer to start of mmaped block>, <size of mmaped block>); 

std::string sv; 
std::string iv; 

while(str >> sv >> iv) 
{ 
    // do stuff... 
} 

我認爲應該工作...

警告這是實現定義的行爲,請參閱this answer,以獲得更好的方法。

+0

我記得,'std :: basic_streambuf :: setbuf'是受保護的。 – ildjarn 2011-03-01 12:06:51

+0

@ildjarn,我修正了它,方法應該是'pubsetbuf' - 應該可以工作... – Nim 2011-03-01 12:10:33

+3

事實證明,這是實現定義的:http://stackoverflow.com/a/13059195/636019 – ildjarn 2012-10-24 23:19:22

0

就目前而言,您的問題太模糊,無法回答。

不過,如果你需要做的是讓一些數據出來的文件,你做什麼不想要做的是使用將在mmap編輯區域修改內存的方法。

編輯現在你已經編輯了這個問題更清楚了。作爲一個起點,我會使用一個指針遍歷整個mmap ed文件。提取字符串非常簡單(確切的方法取決於你需要對結果做什麼),整數可以用atoi等提取。

0

您可以通過std::string來訪問它,並使用std::istringstream以依次讀取它。或者使用一些更方便的庫,例如在Qt中,您可以使用從mmaped內存構建的QByteArray上的QTextStream

+0

是的,我想到了,但無法將其映射到std :: string。我怎麼能這樣做? – Marin 2011-03-01 11:39:22

+0

對不起,我以爲'string :: string(const char * s,size_t n);'構造函數只是引用。但顯然它做了一個副本('const char *'...)。然而'QByteArray :: fromRawData()'可以讓你在現有的內存塊上進行操作。但是,您需要保證該'QByteArray'的生命週期內該塊的生命週期。 – 2011-03-01 13:22:37

2

如果通過最好/最快的方式來代表最簡單的代碼,那麼這是一個罕見的場合,其中棄用的std::istrstream完全符合法案;調用istrstream::istrstream(char const*, std::streamsize)構造函數過載,然後像從其他任何std::istream那樣從流中提取數據。 (這不會複製像std::istringstream將底層存儲。)

如果最好的/最快的你的意思是最好的/最快的運行時性能,我不認爲你能擊敗boostspiritqi或手寫解析器,儘管前者在我看來會更容易編寫和維護(如果您以前從未使用過boost.spirit,那麼將庫學習曲線放在一邊)。

+0

eugh - 推薦一個不贊成的類 - tsk tsk tsk ... – Nim 2011-03-01 12:01:11

+0

@Nim當它適合時,它適合。 : - ] – ildjarn 2011-03-01 12:01:58

+0

有沒有更好的方式使用非棄用類 - 請參閱我的答案下面... – Nim 2011-03-01 12:05:32

2

解析由空格分隔的字符串/整數對(即foo 50 bar 20 baz 123)應該是快如閃電的。更重要的因素將是:a)頁面實際上在RAM中,其中mmap本身並不保證
b)緩存行在L1緩存中

雖然mmap在順序訪問中默認已經預讀,磁盤訪問在幾十毫秒,解析一個4k頁的內存是(理想情況下)在幾十微秒。因此,你不能指望預取器保持速度,特別是因爲只要看起來你需要更多的時候它就只能預取(即使假設尋道時間爲零,實際上由於機械磁盤上​​的旋轉延遲實際上保證了前期成本) 。
因此,除非您的總數據只有十幾千字節(在這種情況下,如何儘可能快地做到這一點毫無意義),但在開始掃描之前瘋狂(MADV_WILLNEED)是有意義的,所以操作系統不會等待您的訪問模式觸發其啓發式檢測,而是按順序讀取它可以停止的內容。一旦你超過訪問時間,磁盤帶寬(依次)是巨大的。你仍然可能趕上,但很晚。如果你的數據集足夠大,以至於它可能不適合RAM,那麼對你已經看到的數據調用MADV_DONTNEED是個好主意。

頁面錯誤也是如此,緩存未命中也是如此。來自高速緩存的負載爲1-2個週期,內存負載約爲200-500個週期。
CPU具有順序訪問模式的自動預取功能,但它們是有限的。首先,預取不會發生在頁面邊界上。這是因爲如果是這種情況,那麼自動預取會定期觸發頁面錯誤,這是非常不愉快的。
其次,預取僅在兩次連續錯過之後纔會發生,這是爲了確保預取只在可能有意義時纔會進行。爲每次隨機讀取預取相鄰的高速緩存行都很愚蠢,因爲它會不必要地浪費寶貴的高速緩存行。
第三,預取需要時間,並且一旦CPU觸發啓發式,您就已經在爲數據競爭了,所以早晚比晚些時候更好。
幸運的是,你知道什麼數據,你會想要的,你知道它很長一段時間。因此,您可以提供預取提示,這將爲CPU提供有價值的開端(預取例如提前半個千字節)。