2010-07-27 8 views
11

निम्नलिखित सरल कोड की कल्पना कीजिए:सामान्य प्रकार के मूल्य को बॉक्सिंग के बिना डबल करने के लिए कैसे करें?

public void F<T>(IList<T> values) where T : struct 
{ 
    foreach (T value in values) 
    { 
    double result; 
    if (TryConvertToDouble((object)value, out result)) 
    { 
     ConsumeValue(result); 
    } 
    } 
} 

public void ConsumeValue(double value) 
{ 
} 

ऊपर कोड आपत्ति उठाने का है, जो पाश में मुक्केबाजी में परिणाम कास्टिंग है के साथ समस्या।

क्या समान कार्यक्षमता प्राप्त करने का कोई तरीका है, यानी फॉरेच लूप में मुक्केबाजी का उपयोग किए बिना सभी मूल्यों के साथ उपभोग करें। नोट, कि एफ एक सामान्य विधि होना चाहिए।

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

संपादित

टी कुछ संख्यात्मक प्रकार या bool के होने की गारंटी है।

प्रेरणा। मेटा डेटा संचालित एप्लिकेशन की कल्पना करें, जहां एक एजेंट डेटा स्ट्रीम की रिपोर्ट करता है, जहां डेटा आइटम प्रकार डेटा स्ट्रीम मेटा डेटा के आधार पर गतिशील रूप से उत्सर्जित होता है। कल्पना कीजिए कि सामान्यीकृत इंजन है, जो कुछ एल्गोरिदम के अनुसार संख्यात्मक डेटा धाराओं को सामान्य करना जानता है। इनकमिंग न्यूमेरिक डेटा स्ट्रीम का प्रकार केवल रन टाइम पर जाना जाता है और इसे उस डेटा प्रकार की सामान्य विधि के लिए निर्देशित किया जा सकता है। हालांकि, सामान्य उत्पादक युगल की अपेक्षा करता है और युगल पैदा करता है। यह एक बहुत ही उच्च स्तर का वर्णन है, कृपया इसमें शामिल न हों।

EDIT2

कलाकारों को दोगुना करने के संबंध में। असल में हम निम्न हस्ताक्षर के साथ दोगुना करने के लिए कन्वर्ट करने के लिए एक विधि है:

bool TryConvertToDouble(object value, out double result); 

मैं पहली जगह में उदाहरण में इसका इस्तेमाल किया जाना चाहिए था, लेकिन मैं अंतरिक्ष और लिखित कुछ है कि काम करने के लिए नहीं जा रहा है को बचाने के लिए करना चाहता था। इसे अभी तय करें। ध्यान देने के लिए धन्यवाद।

EDIT3

दोस्तों, वर्तमान कार्यान्वयन मूल्यों बॉक्स करता है। और यहां तक ​​कि यदि मेरे पास इसके प्रदर्शन प्रदर्शन के लिए प्रोफाइलर का निर्णय नहीं है (यदि कोई है), फिर भी मुझे यह जानना दिलचस्प है कि मुक्केबाजी के बिना कोई समाधान है (और स्ट्रिंग में कनवर्ट किए बिना)। मुझे इसे पूरी तरह अकादमिक हित कहते हैं। यह वास्तव में मुझे रूचि देता है, क्योंकि इस तरह की चीजें टेम्पलेट्स के साथ सी ++ में तुच्छ होती हैं, लेकिन, ज़ाहिर है, मैं अभी भी एक और बेवकूफ और व्यर्थ तर्क नहीं कर रहा हूं जो बेहतर है .NET जेनेरिक या सी ++ टेम्पलेट्स। कृपया, इस अंतिम वाक्य को अनदेखा करें।

EDIT4

https://stackoverflow.com/users/267/lasse-v-karlsen जो उत्तर प्रदान करने के लिए धन्यवाद। वास्तव में, मैं अपने कोड नमूना का इस्तेमाल किया है इस तरह एक साधारण वर्ग में लिखने के लिए:

public static class Utils<T> 
{ 
    private static class ToDoubleConverterHolder 
    { 
    internal static Func<T, double> Value = EmitConverter(); 

    private static Func<T, double> EmitConverter() 
    { 
     ThrowIfNotConvertableToDouble(typeof(T)); 

     var method = new DynamicMethod(string.Empty, typeof(double), TypeArray<T>.Value); 
     var il = method.GetILGenerator(); 

     il.Emit(OpCodes.Ldarg_0); 
     if (typeof(T) != typeof(double)) 
     { 
     il.Emit(OpCodes.Conv_R8); 
     } 
     il.Emit(OpCodes.Ret); 

     return (Func<T, double>)method.CreateDelegate(typeof(Func<T, double>)); 
    } 
    } 

    public static double ConvertToDouble(T value) 
    { 
    return ToDoubleConverterHolder.Value(value); 
    } 
} 

कहाँ:

  • ThrowIfNotConvertableToDouble (प्रकार) एक सरल विधि यकीन है कि दिए गए प्रकार दोगुना करने के लिए परिवर्तित किया जा सकता बनाता है , यानी कुछ संख्यात्मक प्रकार या बूल।
  • TypeArray एक सहायक वर्ग new[]{ typeof(T) }

Utils.ConvertToDouble विधि किसी भी सांख्यिक मान लिए सबसे कारगर तरीका में दोगुना करने के लिए, इस सवाल का जवाब द्वारा दिखाए गए धर्मान्तरित उत्पादन होता है।

यह एक आकर्षण की तरह काम करता है - धन्यवाद आदमी।

+7

समस्या से ऊपर के साथ है कि यह ज्यादा मतलब नहीं है भी है। एक बाधा के साथ एक सामान्य विधि का उपयोग क्यों करें, और फिर इसे दो बार तक डाला जाए? क्या आप स्पष्ट रूप से समझा सकते हैं कि आप क्या हासिल करने की कोशिश कर रहे हैं? –

+0

यह सिर्फ मेरे लिए अजीब लगता है। आप किसी ऑब्जेक्ट के लिए जेनेरिक स्ट्रक्चर कास्टिंग क्यों कर रहे हैं और फिर डबल पर? क्या इस उदाहरण के साथ कुछ गलत है? क्या हमें और संदर्भ की आवश्यकता है? यह कोड जगह से बाहर लगता है, मुझे नहीं पता कि इसका उत्तर कैसे दिया जाए ... –

+0

मैंने प्रश्न अपडेट किया है। – mark

उत्तर

7

नोट: उदाहरण-आधारित कोड जनरेशन के लिए मेरे प्रारंभिक कोड में एक बग था। कृपया नीचे दिए गए कोड को दोबारा जांचें। बदले गए हिस्से को स्टैक पर मूल्य लोड करने का क्रम है (यानी प्रवेश लाइन)। उत्तर और भंडार दोनों कोड को ठीक कर दिया गया है।

यह ConsumeValue (जो मेरे उदाहरण में कुछ नहीं करता है) निष्पादित करता है 10 लाख बार, एक सरणी पर:

आप कोड पीढ़ी के मार्ग से जाने के लिए, के रूप में आप अपने प्रश्न में करने के लिए संकेत चाहते हैं, यहाँ नमूना कोड चींटियों और बुलियन की एक सरणी, निष्पादन का समय (यह एक बार सभी कोड चलाता है, समय को छोड़ने से जेआईटी ओवरहेड को हटाने के लिए।)

उत्पादन: कोड पीढ़ी के साथ

F1 ints = 445ms   <-- uses Convert.ToDouble 
F1 bools = 351ms 
F2 ints = 159ms   <-- generates code on each call 
F2 bools = 167ms 
F3 ints = 158ms   <-- caches generated code between calls 
F3 bools = 163ms 

मोटे तौर पर 65% कम भूमि के ऊपर।

कोड यहां मेरे Mercurial भंडार से उपलब्ध है: http://hg.vkarlsen.no/hgweb.cgi/StackOverflow, अपने SO प्रश्न संख्या को ढूँढकर इसे ब्राउज़ करें।

कोड:

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Linq; 
using System.Reflection; 
using System.Reflection.Emit; 

namespace ConsoleApplication15 
{ 
    class Program 
    { 
     public static void F1<T>(IList<T> values) where T : struct 
     { 
      foreach (T value in values) 
       ConsumeValue(Convert.ToDouble(value)); 
     } 

     public static Action<T> GenerateAction<T>() 
     { 
      DynamicMethod method = new DynamicMethod(
       "action", MethodAttributes.Public | MethodAttributes.Static, 
       CallingConventions.Standard, 
       typeof(void), new Type[] { typeof(T) }, typeof(Program).Module, 
       false); 
      ILGenerator il = method.GetILGenerator(); 

      il.Emit(OpCodes.Ldarg_0); // get value passed to action 
      il.Emit(OpCodes.Conv_R8); 
      il.Emit(OpCodes.Call, typeof(Program).GetMethod("ConsumeValue")); 
      il.Emit(OpCodes.Ret); 

      return (Action<T>)method.CreateDelegate(typeof(Action<T>)); 
     } 

     public static void F2<T>(IList<T> values) where T : struct 
     { 
      Action<T> action = GenerateAction<T>(); 
      foreach (T value in values) 
       action(value); 
     } 

     private static Dictionary<Type, object> _Actions = 
      new Dictionary<Type, object>(); 
     public static void F3<T>(IList<T> values) where T : struct 
     { 
      Object actionObject; 
      if (!_Actions.TryGetValue(typeof(T), out actionObject)) 
      { 
       actionObject = GenerateAction<T>(); 
       _Actions[typeof (T)] = actionObject; 
      } 
      Action<T> action = (Action<T>)actionObject; 
      foreach (T value in values) 
       action(value); 
     } 

     public static void ConsumeValue(double value) 
     { 
     } 

     static void Main(string[] args) 
     { 
      Stopwatch sw = new Stopwatch(); 

      int[] ints = Enumerable.Range(1, 10000000).ToArray(); 
      bool[] bools = ints.Select(i => i % 2 == 0).ToArray(); 

      for (int pass = 1; pass <= 2; pass++) 
      { 
       sw.Reset(); 
       sw.Start(); 
       F1(ints); 
       sw.Stop(); 
       if (pass == 2) 
        Console.Out.WriteLine("F1 ints = " 
         + sw.ElapsedMilliseconds + "ms"); 

       sw.Reset(); 
       sw.Start(); 
       F1(bools); 
       sw.Stop(); 
       if (pass == 2) 
        Console.Out.WriteLine("F1 bools = " 
         + sw.ElapsedMilliseconds + "ms"); 

       sw.Reset(); 
       sw.Start(); 
       F2(ints); 
       sw.Stop(); 
       if (pass == 2) 
        Console.Out.WriteLine("F2 ints = " 
         + sw.ElapsedMilliseconds + "ms"); 

       sw.Reset(); 
       sw.Start(); 
       F2(bools); 
       sw.Stop(); 
       if (pass == 2) 
        Console.Out.WriteLine("F2 bools = " 
         + sw.ElapsedMilliseconds + "ms"); 

       sw.Reset(); 
       sw.Start(); 
       F3(ints); 
       sw.Stop(); 
       if (pass == 2) 
        Console.Out.WriteLine("F3 ints = " 
         + sw.ElapsedMilliseconds + "ms"); 

       sw.Reset(); 
       sw.Start(); 
       F3(bools); 
       sw.Stop(); 
       if (pass == 2) 
        Console.Out.WriteLine("F3 bools = " 
         + sw.ElapsedMilliseconds + "ms"); 
      } 
     } 
    } 
} 

नोट अगर आप GenerationAction, F2/3 और ConsumeValue गैर स्थिर बनाने के लिए, आप कोड थोड़ा बदलना होगा:

  1. सभी Action<T> घोषणाओं Action<Program, T>
  2. हो जाता है
  3. "यह" पैरामीटर शामिल करने के लिए DynamicMethod के निर्माण को बदलें:

    उचित समय पर उचित मूल्यों लोड करने के लिए
    DynamicMethod method = new DynamicMethod(
        "action", MethodAttributes.Public | MethodAttributes.Static, 
        CallingConventions.Standard, 
        typeof(void), new Type[] { typeof(Program), typeof(T) }, 
        typeof(Program).Module, 
        false); 
    
  4. बदलें निर्देश:

    il.Emit(OpCodes.Ldarg_0); // get "this" 
    il.Emit(OpCodes.Ldarg_1); // get value passed to action 
    il.Emit(OpCodes.Conv_R8); 
    il.Emit(OpCodes.Call, typeof(Program).GetMethod("ConsumeValue")); 
    il.Emit(OpCodes.Ret); 
    
  5. पास "इस" कार्रवाई जब भी यह कहा जाता है:

    action(this, value); 
    

यहाँ गैर स्थैतिक तरीकों के लिए पूर्ण रूप से परिवर्तित कार्यक्रम:

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Linq; 
using System.Reflection; 
using System.Reflection.Emit; 

namespace ConsoleApplication15 
{ 
    class Program 
    { 
     public void F1<T>(IList<T> values) where T : struct 
     { 
      foreach (T value in values) 
       ConsumeValue(Convert.ToDouble(value)); 
     } 

     public Action<Program, T> GenerateAction<T>() 
     { 
      DynamicMethod method = new DynamicMethod(
       "action", MethodAttributes.Public | MethodAttributes.Static, 
       CallingConventions.Standard, 
       typeof(void), new Type[] { typeof(Program), typeof(T) }, 
       typeof(Program).Module, 
       false); 
      ILGenerator il = method.GetILGenerator(); 

      il.Emit(OpCodes.Ldarg_0); // get "this" 
      il.Emit(OpCodes.Ldarg_1); // get value passed to action 
      il.Emit(OpCodes.Conv_R8); 
      il.Emit(OpCodes.Call, typeof(Program).GetMethod("ConsumeValue")); 
      il.Emit(OpCodes.Ret); 

      return (Action<Program, T>)method.CreateDelegate(
       typeof(Action<Program, T>)); 
     } 

     public void F2<T>(IList<T> values) where T : struct 
     { 
      Action<Program, T> action = GenerateAction<T>(); 
      foreach (T value in values) 
       action(this, value); 
     } 

     private static Dictionary<Type, object> _Actions = 
      new Dictionary<Type, object>(); 
     public void F3<T>(IList<T> values) where T : struct 
     { 
      Object actionObject; 
      if (!_Actions.TryGetValue(typeof(T), out actionObject)) 
      { 
       actionObject = GenerateAction<T>(); 
       _Actions[typeof (T)] = actionObject; 
      } 
      Action<Program, T> action = (Action<Program, T>)actionObject; 
      foreach (T value in values) 
       action(this, value); 
     } 

     public void ConsumeValue(double value) 
     { 
     } 

     static void Main(string[] args) 
     { 
      Stopwatch sw = new Stopwatch(); 

      Program p = new Program(); 
      int[] ints = Enumerable.Range(1, 10000000).ToArray(); 
      bool[] bools = ints.Select(i => i % 2 == 0).ToArray(); 

      for (int pass = 1; pass <= 2; pass++) 
      { 
       sw.Reset(); 
       sw.Start(); 
       p.F1(ints); 
       sw.Stop(); 
       if (pass == 2) 
        Console.Out.WriteLine("F1 ints = " 
         + sw.ElapsedMilliseconds + "ms"); 

       sw.Reset(); 
       sw.Start(); 
       p.F1(bools); 
       sw.Stop(); 
       if (pass == 2) 
        Console.Out.WriteLine("F1 bools = " 
         + sw.ElapsedMilliseconds + "ms"); 

       sw.Reset(); 
       sw.Start(); 
       p.F2(ints); 
       sw.Stop(); 
       if (pass == 2) 
        Console.Out.WriteLine("F2 ints = " 
         + sw.ElapsedMilliseconds + "ms"); 

       sw.Reset(); 
       sw.Start(); 
       p.F2(bools); 
       sw.Stop(); 
       if (pass == 2) 
        Console.Out.WriteLine("F2 bools = " 
         + sw.ElapsedMilliseconds + "ms"); 

       sw.Reset(); 
       sw.Start(); 
       p.F3(ints); 
       sw.Stop(); 
       if (pass == 2) 
        Console.Out.WriteLine("F3 ints = " 
         + sw.ElapsedMilliseconds + "ms"); 

       sw.Reset(); 
       sw.Start(); 
       p.F3(bools); 
       sw.Stop(); 
       if (pass == 2) 
        Console.Out.WriteLine("F3 bools = " 
         + sw.ElapsedMilliseconds + "ms"); 
      } 
     } 
    } 
} 
+0

वाह। बहुत रोचक, यह मुझे सत्यापित करने के लिए कुछ समय ले रहा है, लेकिन वादा करता है। – mark

+0

कृपया सुनिश्चित करें कि आप सत्यापित करते हैं कि आप कोड के सही संस्करण का उपयोग कर रहे हैं। मैंने बस उत्सर्जित निर्देशों के क्रम में एक बग तय किया। –

+0

आप कुछ सिंगलटन-जैसे स्लॉट á la 'ConvertAction में जेनरेट की गई कार्रवाई को कैश करके भी प्रदर्शन बढ़ा सकते हैं। इस तरह आपको एक शब्दकोश के साथ परेशानी नहीं होगी और थ्रेड-सुरक्षा के बारे में चिंता नहीं करनी पड़ेगी। – herzmeister

0

आप Convert कक्षा का उपयोग कर सकते हैं।

ConsumeValue(Convert.ToDouble(value)); 

ToDouble के आंतरिक के बारे में निश्चित नहीं है ... लेकिन शायद आप सबसे अच्छा कर सकते हैं।

+0

नहीं, मैं नहीं कर सकता। कनवर्ट करें। दोहरी एक सामान्य विधि नहीं है। – mark

+0

सी # 3.0 (नेट 3.5) –

+0

में ठीक काम करता है क्योंकि ऐसा होता है क्योंकि टी को ऑब्जेक्ट करने के लिए डाला जाता है और फिर कनवर्ट किया जाता है। दोहरी (ऑब्जेक्ट) अधिभार कहा जाता है - आपने स्पष्ट मुक्केबाजी को एक अंतर्निहित व्यापार किया है। अपने लिए जांचें। – mark

0

क्यों न केवल double - सामान्य संस्करण के साथ F के लिए विशिष्ट अधिभार क्यों जोड़ें?

public void F(IList<double> values) 
{ 
    foreach (double value in values) 
    { 
     ConsumeValue(value); 
    } 
} 

अब अगर आप F(someDoubleList) फोन यह गैर जेनेरिक वर्जन फोन करता हूँ, और किसी भी अन्य की सूची के साथ सामान्य से एक कहा जाता हो जाएगा।

+0

मेरे पास IList उदाहरण है। यह एक दिया गया है। मैं इसे IList कैसे बना सकता हूं? – mark

+0

'if (typeof (टी) == टाइपऑफ (डबल)) IList dlist = (IList ) सूची ' – thecoop

+0

और यदि टाइप टाइप (टी) == टाइपऑफ (int)? या टाइपोफ (फ्लोट) या टाइपफ (यूंट)? – mark

0

हालांकि परिदृश्य अभी भी बहुत स्पष्ट नहीं है (मेरी टिप्पणी देखें), यह कभी काम नहीं करेगा। आपको एक कस्टम क्लास या विधि प्रदान करनी होगी जो आपके जेनेरिक टी से दोगुनी हो सकती है।

unboxing

ConsumeValue((double)(object)value); 

में डाली फेंक होगा एक InvalidCastException अगर value एक double ही नहीं है के रूप में, यहां तक ​​कि प्रासंगिक नहीं है। (this एरिक लिपर्ट द्वारा ब्लॉग प्रविष्टि कारणों के कारण देखें।)

आपको इनपुट को प्रीप्रोसेस करना होगा, सामान्य संस्करण काम नहीं करेगा।

संपादित करें:

मैं Convert.ToDouble निर्णय लेना होगा। केवल अगर प्रदर्शन ab-so-lu-te-ly शीर्ष प्राथमिकता है, तो मैं गतिशील विधि के साथ जाऊंगा। यदि संभव हो, तो इससे बचने के लिए यह पर्याप्त जटिलता जोड़ता है। लगभग 50% का प्रदर्शन लाभ निश्चित रूप से महत्वपूर्ण दिखता है, लेकिन, लाससे द्वारा दिए गए परिदृश्य में, मेरी मशीन पर 10000000 (दस मिलियन) वस्तुओं को फिर से शुरू करते समय मुझे लगभग 150 मिलीमीटर मिलते हैं, जिससे आप प्रत्येक पुनरावृत्ति को 0,000015 मिलीसेकंड बचाते हैं।

+0

आप सही हैं। मैं बस इतना आसान उदाहरण देना चाहता था और केवल सादा खराब कोड के साथ समाप्त हुआ। इस दुर्भाग्यपूर्ण गलती को सही करने के लिए प्रश्न संपादित किया। – mark

+0

आप कन्वर्ट का उपयोग कर सकते हैं। अन्य उत्तरों द्वारा सुझाए गए डबल। लेकिन जैसा कि मैं समझता हूं कि आप मुक्केबाजी/अनबॉक्सिंग के कारण प्रदर्शन के मुद्दे से चिंतित हैं। उस मामले में कनवर्ट करें। दोहरी एक बदतर पसंद हो सकती है। फिर भी, जब तक कि परीक्षण पहले से ही दिखाए गए हैं कि रूपांतरण वास्तव में एक बाधा है, मैं इसके लिए जाऊंगा। –

+0

अभी तक मेरे प्रश्न संपादित करें। – mark

4

यह एक अच्छा सवाल है, मेरे पास यह कार्य भी था और मैं संकलित लिंक अभिव्यक्तियों का उपयोग कर आया था ताकि मुक्केबाजी से बचने वाले सामान्य प्रकार के मानकों से और उसके प्रकार के मूल्य प्रकारों के मनमानी रूपांतरण किए जा सकें। समाधान बहुत प्रभावी और तेज़ है। यह एक सिंगलटन में एक संकलित लैम्ब्डा प्रति मान प्रकार को स्टोर करता है। उपयोग स्वच्छ और पठनीय है।

यहाँ एक सरल वर्ग कि काम बहुत अच्छी तरह से करता है:

public sealed class BoxingSafeConverter<TIn, TOut>   
{ 
    public static readonly BoxingSafeConverter<TIn, TOut> Instance = new BoxingSafeConverter<TIn, TOut>(); 
    private readonly Func<TIn, TOut> convert;   

    public Func<TIn, TOut> Convert 
    { 
     get { return convert; } 
    } 

    private BoxingSafeConverter() 
    { 
     if (typeof (TIn) != typeof (TOut)) 
     { 
      throw new InvalidOperationException("Both generic type parameters must represent the same type."); 
     } 
     var paramExpr = Expression.Parameter(typeof (TIn)); 
     convert = 
      Expression.Lambda<Func<TIn, TOut>>(paramExpr, // this conversion is legal as typeof(TIn) = typeof(TOut) 
       paramExpr) 
       .Compile(); 
    } 
} 

अब कल्पना करें कि आप वस्तुओं और युगल के साथ कुछ भंडारण करना चाहते हैं और आप अपने युगल बॉक्सिंग जा करने के लिए नहीं करना चाहती। ,

public class MyClass 
{ 
    readonly List<double> doubles = new List<double>(); // not boxed doubles 
    readonly List<object> objects = new List<object>(); // all other objects 

    public void BoxingSafeAdd<T>(T val) 
    { 
     if (typeof (T) == typeof (double)) 
     { 
      // T to double conversion 
      doubles.Add(BoxingSafeConverter<T, double>.Instance.Convert(val)); 
      return; 
     } 

     objects.Add(val); 
    } 

    public T BoxingSafeGet<T>(int index) 
    { 
     if (typeof (T) == typeof (double)) 
     { 
      // double to T conversion 
      return BoxingSafeConverter<double, T>.Instance.Convert(doubles[index]); 
     } 

     return (T) objects[index]; // boxing-unsage conversion 
    } 
} 

यहाँ जो पता चलता है कि अनबॉक्स्ड मानों का उपयोग कर आप स्मृति का एक बहुत बचा सकता है MyClass के कुछ सरल प्रदर्शन और स्मृति परीक्षण कर रहे हैं जी सी के दबाव को कम: आप सामान्य getters और निम्नलिखित तरीके से setters के साथ इस तरह वर्ग लिख सकता है और प्रदर्शन ओवरहेड बहुत छोटा है: बस लगभग 5-10%।

1. मुक्केबाजी के साथ:

 const int N = 1000000; 
     MyClass myClass = new MyClass(); 

     double d = 0.0; 
     var sw = Stopwatch.StartNew(); 
     for (int i = 0; i < N; i++, d += 0.1) 
     { 
      myClass.BoxingSafeAdd((object)d); 
     } 
     Console.WriteLine("Time: {0} ms", sw.ElapsedMilliseconds); 

     Console.WriteLine("Memory: {0} MB.", (double)GC.GetTotalMemory(false)/1024/1024); 

परिणाम:

Time: 130 ms 
Memory: 19.7345771789551 MB 

2।मुक्केबाजी के बिना

 const int N = 1000000; 
     MyClass myClass = new MyClass(); 

     double d = 0.0; 
     var sw = Stopwatch.StartNew(); 
     for (int i = 0; i < N; i++, d += 0.1) 
     { 
      myClass.BoxingSafeAdd(d); 
     } 
     Console.WriteLine("Time: {0} ms", sw.ElapsedMilliseconds); 

     Console.WriteLine("Memory: {0} MB", (double)GC.GetTotalMemory(false)/1024/1024); 

परिणाम:

Time: 144 ms 
Memory: 12.4955024719238 MB 
+0

यह मेरे लिए बहुत अच्छा लग रहा है। मैं (मामूली) प्रदर्शन ओवरहेड देखने के लिए हैरान हूँ। मुझे उम्मीद है कि संकलित लैम्ब्डा इसे मुक्केबाजी से तेज कर देगा। कोई विचार क्यों नहीं है? – Timo

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