我正在解析大小約爲1MB的文件,讀取第一個300KB並搜索大量特定簽名。我的策略是,對於每個字節,查看該字節是否在映射/向量中/我知道可能在簽名開始處的任何字節,如果是這樣,請查找完整簽名 - 對於此示例,假設這些前導字節是x37,x50和x52。處理總共90個文件(9個文件10倍實際上),下面的代碼執行2.122秒:爲什麼矢量和地圖搜索比靜態比較慢得多
byte * bp = &buffer[1];
const byte * endp = buffer + bytesRead - 30; // a little buffer for optimization - no signature is that long
//multimap<byte, vector<FileSignature> >::iterator lb, ub;
map<byte, vector<FileSignature> >::iterator findItr;
vector<FileSignature>::iterator intItr;
while (++bp != endp)
{
if (*bp == 0x50 || *bp == 0x52 || *bp == 0x37) // Comparison line
{
findItr = mapSigs.find(*bp);
for (intItr = findItr->second.begin(); intItr != findItr->second.begin(); intItr++)
{
bool bMatch = true;
for (UINT i = 1; i < intItr->mSignature.size(); ++i)
{
if (intItr->mSignature[i] != bp[i])
{
bMatch = false;
break;
}
}
if (bMatch)
{
CloseHandle(fileHandle);
return true;
}
}
}
}
然而,我的初始執行以一種緩慢的84秒完成。唯一的差別是與標記爲「//比較線」上方的行:
findItr = mapSigs.find(*bp);
if (findItr != mapSigs.end())
...
一個非常類似的實現使用含有3個值還導致極其緩慢處理(190秒)向量:
if (find(vecFirstChars.begin(), vecFirstChars.end(), *bp) != vecFirstChars.end())
{
findItr = mapSigs.find(*bp);
...
但訪問矢量元素的實現直接執行得很好(8.1秒)。不如靜態比較,但仍遠高於其他選項好得多:
if (vecFirstChars[0] == *bp || vecFirstChars[1] == *bp || vecFirstChars[2] == *bp)
{
findItr = mapSigs.find(*bp);
...
最快的實現到目前爲止(由下面組件10啓發)如下,以約2.0秒打卡:
bool validSigs[256] = {0};
validSigs[0x37] = true;
validSigs[0x50] = true;
validSigs[0x52] = true;
while (++bp != endp)
{
if (validSigs[*bp])
{
...
將其擴展爲使用2個validSigs來查看第二個字符是否有效以及總運行時間降至0.4秒。
我覺得其他的實現應該更好。尤其是地圖應該按照更多的簽名前綴進行縮放,並且搜索是O(log(n))和O(n)。我錯過了什麼?我唯一的黑暗中猜測是,通過靜態比較和向量索引(對於較小的現有值),我將得到的值用於緩存在寄存器或其他位置的比較值,這使得它比閱讀速度快得多從記憶裏。如果這是真的,我能夠明確告訴編譯器經常使用特定值嗎?有沒有其他優化方法可以利用下面的代碼不明顯?
我與Visual Studio 2008編譯
您的預先過濾只有三個值肯定會加快速度,因爲它實際上會拋出其他可能的253個已知未命中條件。在地圖上只有三個值,我真的不明白爲什麼你有一個。對三個值(你已經在做)進行內聯測試並打上適當的後續列表也會更快。如果這全部是關於搜索子字符串(字節等),我建議你閱讀有關[Knuth-Morris-Pratt](http://en.wikipedia.org/wiki/Knuth-Morris-Pratt_algorithm)等算法 – WhozCraig
你考慮使用一個稀疏矢量作爲你的簽名值?聽起來像這可能是在這些情況下體面優化,特別是如果您的簽名的範圍是一個字節。 –
我還沒有讀過關於Knuth-Morris-Pratt的文章 - 有趣的閱讀,但不太適用。假設字節的均勻分佈,我只會看到每256個比較中的第3個(或7個)第一個字符的匹配。當我得到一場比賽時,每個後續角色的匹配機率更低(1/256)。我不認爲這裏會有很多好處。 @ Component10我不知道一個稀疏矢量會有幫助,但是一個連續的數組會加速它 - 更新問題與另一個案例。 – Rollie