2012-01-20 12 views
10

मैंने समानता (बाइट-फॉर-बाइट) के लिए दो धाराओं की तुलना करने के लिए एक विस्तार विधि अनुकूलित की - यह जानकर कि यह एक गर्म विधि है जिसे मैंने यथासंभव अनुकूलित करने की कोशिश की है (धाराएं बहु-मेगाबाइट लंबाई तक पहुंच सकते हैं)। मैं अनिवार्य रूप से निम्नलिखित दृष्टिकोण के साथ आया था:अगर स्टेटमेंट ट्रू ब्लॉक निष्पादित होता है तो कंडीशन गलत होती है

[StructLayout(LayoutKind.Explicit)] 
struct Converter 
{ 
    [FieldOffset(0)] 
    public Byte[] Byte; 

    [FieldOffset(0)] 
    public UInt64[] UInt64; 
} 

/// <summary> 
/// Compares two streams for byte-by-byte equality. 
/// </summary> 
/// <param name="target">The target stream.</param> 
/// <param name="compareTo">The stream to compare the target to.</param> 
/// <returns>A value indicating whether the two streams are identical.</returns> 
public static bool CompareBytes(this Stream target, Stream compareTo) 
{ 
    if (target == null && compareTo == null) 
     return true; 
    if (target == null || compareTo == null) 
     return false; 
    if (target.Length != compareTo.Length) 
     return false; 
    if (object.ReferenceEquals(target, compareTo)) 
     return true; 
    if (!target.CanRead || !target.CanSeek) 
     throw new ArgumentOutOfRangeException("target"); 
    if (!compareTo.CanRead || !compareTo.CanSeek) 
     throw new ArgumentOutOfRangeException("target"); 
    lock (target) 
    { 
     lock (compareTo) 
     { 
      var origa = target.Position; 
      var origb = compareTo.Position; 
      try 
      { 
       target.Position = compareTo.Position = 0; 

       // Shrink the number of comparisons. 
       var arr1 = new byte[4096]; 
       var convert1 = new Converter() { Byte = arr1 }; 
       var arr2 = new byte[4096]; 
       var convert2 = new Converter() { Byte = arr2 }; 

       int len; 
       while ((len = target.Read(arr1, 0, 4096)) != 0) 
       { 
        if (compareTo.Read(arr2, 0, 4096) != len) 
         return false; 
        for (var i = 0; i < (len/8) + 1; i++) 
         if (convert1.UInt64[i] != convert2.UInt64[i]) 
          return false; 
       } 

       return true; 
      } 
      finally 
      { 
       target.Position = origa; 
       compareTo.Position = origb; 
      } 
     } 
    } 
} 

समस्या यह है कि convert1.UInt64[i] != convert2.UInt64[i]if ब्लॉक (false लौटने) मूल्यांकन किया जा रहा है, तब भी जब मान बराबर हो रहा है। मैंने व्यक्तिगत रूप से प्रत्येक को चेक किया, फिर 'बराबर नहीं' के नतीजे की जांच की। मैं शुद्ध अविश्वास में हूँ:

Values are not equal

मैं अनुदेश सूचक के साथ गड़बड़ नहीं है - यह कैसे कोड निष्पादित और घड़ी पिन लाइव है।

कोई विचार यह कैसे हो सकता है?

+0

यह काम करता है यदि आप {} – rerun

+1

एक तुलना तुलना की तरह दिखते हैं (अलग ऑब्जेक्ट्स, हमेशा झूठी) मूल्य तुलना – Alex

+0

के बजाय हो रहा है, मैं उलझन में हूं, दोनों संरचना गुणों में फ़ील्डऑफसेट 0 है, आप कैसे जानते हैं सेब और सेब की तुलना कर रहे हैं? – mtijn

उत्तर

11
for (var i = 0; i < (len/8) + 1; i++) 

सामान्य रूप से डीबगर इस संघ के साथ कठिन समय है, जब मैं इसे कोशिश करता हूं तो यह सरणी सामग्री प्रदर्शित नहीं कर सकता है। लेकिन मूल समस्या में() अंत अभिव्यक्ति के लिए +1 में कोई संदेह नहीं है। यह लेन द्वारा विभाजित होने पर सरणी को अपने अंतिम तत्व से परे अनुक्रमित करता है 8. रनटाइम इस गलती को नहीं पकड़ सकता है, सरणी को ओवरलैप करने से लम्बाई संपत्ति का फर्जी मूल्य होता है। अगला क्या होता है अपरिभाषित व्यवहार, आप बाइट पढ़ रहे हैं जो सरणी का हिस्सा नहीं हैं। सरणी 7 बाइट लंबा बनाने के लिए एक कामकाज है।

इस प्रकार का कोड बिल्कुल अनुकूलन नहीं है, 32-बिट मशीन पर uint64 को पढ़ने और तुलना करना महंगा है, खासकर जब सरणी सही ढंग से संरेखित नहीं होती है .. इसके लिए लगभग 50% बाधाएं।

[DllImport("msvcrt.dll")] 
    private static extern int memcmp(byte[] arr1, byte[] arr2, int cnt); 

और इस तरह इसका इस्तेमाल:

int len; 
    while ((len = target.Read(arr1, 0, 4096)) != 0) { 
     if (compareTo.Read(arr2, 0, 4096) != len) return false; 
     if (memcmp(arr1, arr2, len) != 0) return false; 
    } 
    return true; 

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

+0

धन्यवाद हंस। मैंने +1 को 'अधिकतम' कॉल में रखने के बारे में सोचा था।आपने मेरे प्रश्न का उत्तर दिया है और ऊपर और परे चला गया है और मुझे एक बेहतर अनुकूलन प्रदान किया है। एक अच्छी तरह से योग्य टिक! –

1

इस तरह की समस्याएं आमतौर पर ऑप्टिमाइज़ेशन कैसे काम करती हैं, इसकी समझ के साथ समस्याएं होती हैं। कोड की यह पंक्ति बहुत अच्छी तरह से निष्पादित की जा सकती है क्योंकि दोनों झूठे खंड लौटते हैं, निचले स्तर पर निर्देशों के एक सेट में संयुक्त होते हैं। इस तरह के मुद्दों के लिए अन्य कारण यह है कि यदि आप जिस आर्किटेक्चर पर हैं, वह सशर्त निष्पादन की अनुमति देता है जिसमें डीबगर में कुछ निर्देश दिए जाते हैं लेकिन परिणाम आर्किटेक्चर स्तर पर रजिस्टरों के लिए कभी प्रतिबद्ध नहीं होते हैं।

सत्यापित करें कि कोड पहले डीबग मोड में काम करता है। फिर जब आप आश्वस्त होते हैं तो परिणाम रिलीज मोड के समान होता है, तो हाथ में कंपाइलर अनुकूलन को समझने के लिए अंतर्निहित निर्देशों को देखें।

+0

कोड वर्तमान में डीबग है - यहां तक ​​कि मुझे लगता है कि जेआईटीटर इसे एक फैशन में अनुकूलित नहीं करेगा जो इसे तोड़ देगा। मैं dissasembly का निरीक्षण करेंगे और देखें कि कवर के तहत क्या चल रहा है। –

संबंधित मुद्दे