2010-01-31 8 views
14

डिस्क पर वास्तव में एक बड़ी फ़ाइल (शायद 4 जीबी से अधिक) को ध्यान में रखते हुए, मैं इस फ़ाइल के माध्यम से स्कैन करना चाहता हूं और विशिष्ट बाइनरी पैटर्न के समय की गणना करना चाहता हूं।डिस्क पर वास्तव में बड़ी फ़ाइलों के माध्यम से स्कैन कैसे करें?

मेरे बारे में सोचा है:

  1. उपयोग स्मृति-मैप की गई फ़ाइल (CreateFileMap या mapped_file को बढ़ावा देने) आभासी स्मृति को फ़ाइल को लोड करने।

  2. प्रत्येक 100 एमबी मैप-मेमोरी के लिए, स्कैन करने और परिणाम की गणना करने के लिए एक थ्रेड बनाएं।

क्या यह संभव है? क्या ऐसा करने के लिए कोई बेहतर तरीका है?

अद्यतन:
मेमोरी-मैप किया फ़ाइल एक 1.6GB फ़ाइल 11s के भीतर नियंत्रित किया जा सकता है के माध्यम से scaning के लिए, एक अच्छा विकल्प होगा।

धन्यवाद।

+4

(2) मई पैटर्न 100 एमबी सीमा तक फैला सकता है? यदि आपको खोज एल्गोरिदम स्वयं लिखना है, और खोज-स्ट्रिंग उचित रूप से लंबी है (अब बेहतर है!), बॉयर-मूर एल्गोरिदम पर विचार करें http://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string_search_algorithm – Kristen

+0

@ क्रिस्टन: पैटर्न 100 एमबी सीमा नहीं फैलाएगा, क्योंकि पैटर्न थोड़ा '1' है। – Jichao

+0

पैटर्न क्या है, क्या यह वास्तव में एक सेट बिट है? – GalacticJello

उत्तर

4

मल्टीथ्रेडिंग केवल यह धीमा होने जा रहा है जब तक आप एक अलग हार्ड ड्राइव पर प्रत्येक के साथ एकाधिक फ़ाइलों को स्कैन नहीं करना चाहते हैं। अन्यथा आप बस खोज रहे हैं।

मैंने मेमोरी मैप की गई फ़ाइलों का उपयोग करके एक सरल परीक्षण फ़ंक्शन लिखा, एक थ्रेड के साथ एक 1.4 जीबी फ़ाइल स्कैन करने में लगभग 20 सेकंड लग गई। दो धागे के साथ, प्रत्येक आधा फ़ाइल लेता है (यहां तक ​​कि 1 एमबी भाग एक धागे तक, दूसरे के लिए अजीब), इसमें 80 सेकंड से अधिक समय लगा।

  • 1 धागा: 20015 मिलीसेकंड
  • 2 धागे: 83,985 मिलीसेकंड

यह सही है, 2 धागे चार बार 1 धागा की तुलना में धीमी थी!

यहां मेरे द्वारा उपयोग किया जाने वाला कोड है, यह एकल थ्रेडेड संस्करण है, मैंने 1 बाइट स्कैन पैटर्न का उपयोग किया था, इसलिए नक्शा सीमाओं को पार करने वाले मैचों का पता लगाने के लिए कोड अनचाहे है।

HRESULT ScanForPattern(LPCTSTR pszFilename, LPBYTE pbPattern, UINT cbPattern, LONGLONG * pcFound) 
{ 
    HRESULT hr = S_OK; 

    *pcFound = 0; 
    if (! pbPattern || ! cbPattern) 
     return E_INVALIDARG; 

    // Open the file 
    // 
    HANDLE hf = CreateFile(pszFilename, 
          GENERIC_READ, 
          FILE_SHARE_READ, NULL, 
          OPEN_EXISTING, 
          FILE_FLAG_SEQUENTIAL_SCAN, 
          NULL); 

    if (INVALID_HANDLE_VALUE == hf) 
     { 
     hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); 
     // catch an open file that exists but is in use 
     if (ERROR_SHARING_VIOLATION == GetLastError()) 
     hr = HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION); 
     return hr; 
     } 

    // get the file length 
    // 
    ULARGE_INTEGER uli; 
    uli.LowPart = GetFileSize(hf, &uli.HighPart); 
    LONGLONG cbFileSize = uli.QuadPart; 
    if (0 == cbFileSize) 
     { 
     CloseHandle (hf); 
     return S_OK; 
     } 

    const LONGLONG cbStride = 1 * 1024 * 1024; // 1 MB stride. 
    LONGLONG cFound = 0; 
    LPBYTE pbGap = (LPBYTE) malloc(cbPattern * 2); 

    // Create a mapping of the file. 
    // 
    HANDLE hmap = CreateFileMapping(hf, NULL, PAGE_READONLY, 0, 0, NULL); 
    if (NULL != hmap) 
     { 
     for (LONGLONG ix = 0; ix < cbFileSize; ix += cbStride) 
     { 
     uli.QuadPart = ix; 
     UINT cbMap = (UINT) min(cbFileSize - ix, cbStride); 
     LPCBYTE pb = (LPCBYTE) MapViewOfFile(hmap, FILE_MAP_READ, uli.HighPart, uli.LowPart, cbMap); 
     if (! pb) 
      { 
      hr = HRESULT_FROM_WIN32(GetLastError()); 
      break; 
      } 
     // handle pattern scanning over the gap. 
     if (cbPattern > 1 && ix > 0) 
      { 
      CopyMemory(pbGap + cbPattern - 1, &pb[0], cbPattern - 1); 
      for (UINT ii = 1; ii < cbPattern; ++ii) 
       { 
       if (pb[ii] == pbPattern[0] && 0 == memcmp(&pb[ii], pbPattern, cbPattern)) 
        { 
        ++cFound; 
        // advance by cbPattern-1 to avoid detecting overlapping patterns 
        } 
       } 
      } 

     for (UINT ii = 0; ii < cbMap - cbPattern + 1; ++ii) 
      { 
      if (pb[ii] == pbPattern[0] && 
       ((cbPattern == 1) || 0 == memcmp(&pb[ii], pbPattern, cbPattern))) 
       { 
       ++cFound; 
       // advance by cbPattern-1 to avoid detecting overlapping patterns 
       } 
      } 
     if (cbPattern > 1 && cbMap >= cbPattern) 
      { 
      // save end of the view in our gap buffer so we can detect map-straddling patterns 
      CopyMemory(pbGap, &pb[cbMap - cbPattern + 1], cbPattern - 1); 
      } 
     UnmapViewOfFile(pb); 
     } 

     CloseHandle (hmap); 
     } 
    CloseHandle (hf); 

    *pcFound = cFound; 
    return hr; 
} 
+0

प्रश्न: आप "if (pb [ii] == pbPterntern [0] का उपयोग क्यों करते हैं && 0 == memcmp (& pb [ii], pbPattern, cbPattern)) "? Memcmp (& pb [ii], pbPattern, cbPattern) जैसे ही यह पहले बाइट्स की तुलना में झूठी वापसी करेगा यदि वे बराबर नहीं हैं? –

5

हालांकि आप मेमोरी मैपिंग का उपयोग कर सकते हैं, आपको यह नहीं करना है। यदि आप फ़ाइल को अनुक्रमिक रूप से छोटे हिस्सों में पढ़ते हैं, तो प्रत्येक 1 एमबी कहें, फ़ाइल कभी भी स्मृति में कभी भी मौजूद नहीं होगी।

यदि आपका खोज कोड वास्तव में आपकी हार्ड डिस्क की तुलना में धीमा है, तो आप अभी भी कार्यकर्ता धागे को टुकड़े बंद कर सकते हैं।

+0

मुझे डर है कि डिस्क से पढ़ने की तुलना में खोज धीमा हो सकता है, वास्तव में पैथोलॉजिकल मामलों के लिए होगा (उदाहरण के लिए 999,999 'ए' अक्षरों की खोज करना, इसके बाद फ़ाइल में 'बी' के बाद केवल 1,000,000' ए' वर्ण होते हैं) का उपयोग करते समय एक बेवकूफ खोज विधि (जैसे कि आमतौर पर 'strstr()' के लिए लागू)। किसी भी रैखिक-समय स्ट्रिंग खोज (जैसे Knuth-Morris-Pratt) डिस्क I/O कम से कम 100x धीमी होगी। –

+2

हाँ, यही कारण है कि मैंने "अगर" और "वास्तव में" लिखा है "यदि आपका खोज कोड वास्तव में धीमा है ..." :) – Thomas

10

20 थ्रेड बनाना, प्रत्येक 100 एमबी फ़ाइल को संभालने के लिए अनुमान लगाते हुए प्रत्येक प्रदर्शन को खराब कर सकता है क्योंकि एचडी को एक ही समय में कई असंबंधित स्थानों से पढ़ना होगा।

अनुक्रमिक डेटा पढ़ने पर एचडी प्रदर्शन अपने चरम पर है। तो मान लें कि आपकी विशाल फ़ाइल खंडित नहीं है, करने के लिए सबसे अच्छी बात शायद एक धागे का उपयोग करना होगा और कुछ (4 कहें) एमबी के भाग में शुरू से अंत तक पढ़ना होगा।

लेकिन मुझे क्या पता है। फाइल सिस्टम और कैश जटिल हैं। कुछ परीक्षण करें और देखें कि सबसे अच्छा क्या काम करता है।

0

मेमोरी मैप किए गए फ़ाइल का उपयोग करने से फ़ाइल सिस्टम कैश मेमोरी से (प्रबंधित) एप्लिकेशन मेमोरी में एक प्रतिलिपि से बचने का अतिरिक्त लाभ होता है यदि आप केवल पढ़ने के लिए उपयोग करते हैं (हालांकि आपको बाइट * पॉइंटर्स का उपयोग करने के लिए उपयोग करना है याद)। और कई धागे बनाने के बजाए फ़ाइल में 100 एमबी मेमोरी मैप किए गए दृश्यों के लिए अनुक्रमिक रूप से फाइल के माध्यम से स्कैन करने के लिए एक थ्रेड का उपयोग करें (पूरी फाइल को प्रक्रिया पता स्थान में एक बार में मानचित्र न करें)।

0

मैं इसे एक डबल बफर में एसिंक्रोनस पढ़ने के साथ करता हूं। तो जब फ़ाइल से एक बफर पढ़ा गया है, तो पहले बफर स्कैन करते समय अगला बफर पढ़ने शुरू करें। इसका मतलब है कि आप समानांतर में सीपीयू और आईओ करते हैं। एक और फायदा यह है कि आपके पास हमेशा डेटा सीमाओं के आसपास डेटा होगा। हालांकि मुझे नहीं पता कि स्मृति मैप की गई फ़ाइलों के साथ डबल बफरिंग संभव है या नहीं।

उम्मीद है कि इससे मदद मिलती है।

सादर,

Sebastiaan

1

मैं भी केवल एक ही धागे से जाना चाहते हैं न केवल के लिए HD प्रदर्शन के मुद्दों, लेकिन आप मुसीबत जब आपकी फ़ाइल बंटवारे दुष्प्रभाव प्रबंध हो सकता है क्योंकि: वहाँ क्या हुआ अगर एक अपने पैटर्न की घटना जहां आप अपनी फाइल को विभाजित करते हैं?

2

मेरे पास एक थ्रेड फ़ाइल (संभवतः एक स्ट्रीम के रूप में) को एक सरणी में पढ़ेगा और इसमें एक और धागा प्रक्रिया होगी। डिस्क की तलाश के कारण मैं कई बार मैप नहीं करता। मेरे पास शायद मेरे धागे को बताने के लिए मैन्युअल रीसेट इवेंट होगा? बाइट संसाधित होने के लिए तैयार हैं। मान लें कि आपका प्रोसेस कोड तेज है तो एचडीडी में मेरे पास 2 बफर होंगे, एक भरने के लिए और दूसरा प्रक्रिया करने के लिए और बस हर बार उनके बीच स्विच करें।

0

टिम ब्रै (और उनके पाठकों) ने इसे Wide Finder Project और Wide Finder 2 में गहराई से खोजा। Benchmark results दिखाता है कि बहुप्रचारित कार्यान्वयन एक बड़े-थ्रेडेड समाधान को बड़े पैमाने पर सूर्य मल्टीकोर सर्वर पर बेहतर प्रदर्शन कर सकता है। सामान्य पीसी हार्डवेयर पर, मल्टीथ्रेडिंग आपको उतना अधिक लाभ नहीं पहुंचाएगी, अगर बिलकुल भी।