इनवोक और डायनेमिक इंवोक के बीच अंतर


128

प्रतिनिधियों में इन्वोक और डायनामिकवोक के बीच अंतर क्या है? कृपया मुझे कुछ कोड उदाहरण दें जो उन दो तरीकों के बीच अंतर को स्पष्ट करते हैं।

जवाबों:


206

जब आपके पास एक प्रतिनिधि उदाहरण होता है, तो आपको सटीक प्रकार पता हो सकता है, या आप बस यह जान सकते हैं कि यह एक है Delegate। यदि आप सटीक प्रकार जानते हैं, तो आप उपयोग कर सकते हैं Invoke, जो बहुत तेज़ है - सब कुछ पहले से ही पूर्व-मान्य है। उदाहरण के लिए:

Func<int,int> twice = x => x * 2;
int i = 3;
int j = twice.Invoke(i);
// or just:
int j = twice(i);

तथापि! यदि आप बस जानते हैं कि यह है Delegate, तो इसे मैन्युअल रूप से मापदंडों आदि को हल करना होगा - इसमें अनबॉक्सिंग आदि शामिल हो सकते हैं - बहुत अधिक प्रतिबिंब चल रहा है। उदाहरण के लिए:

Delegate slowTwice = twice; // this is still the same delegate instance
object[] args = { i };
object result = slowTwice.DynamicInvoke(args);

नोट मैंने argsयह स्पष्ट करने के लिए लंबा हाथ लिखा है कि object[]इसमें शामिल है। यहां बहुत सारी अतिरिक्त लागतें हैं:

  • सरणी
  • पारित तर्कों को मान्य करना वास्तविक के लिए एक "फिट" है MethodInfo
  • आवश्यक के रूप में unboxing आदि
  • प्रतिबिंब-आह्वान
  • तब कॉलर को रिटर्न वैल्यू को संसाधित करने के लिए कुछ करने की आवश्यकता होती है

मूल रूप से, DynamicInvokeजब आप कर सकते हैं तब से बचें । Invokeहमेशा बेहतर है, जब तक कि आपके पास सब कुछ एक Delegateऔर एक है object[]

प्रदर्शन की तुलना के लिए, डिबगर के बाहर रिलीज़ मोड में (कंसोल कंसोल) प्रिंट करता है:

Invoke: 19ms
DynamicInvoke: 3813ms

कोड:

Func<int,int> twice = x => x * 2;
const int LOOP = 5000000; // 5M
var watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
    twice.Invoke(3);
}
watch.Stop();
Console.WriteLine("Invoke: {0}ms", watch.ElapsedMilliseconds);
watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
    twice.DynamicInvoke(3);
}
watch.Stop();
Console.WriteLine("DynamicInvoke: {0}ms", watch.ElapsedMilliseconds);

3
इसका मतलब यह है कि उपयोग के मामले में डायनामिकइनवॉकर संकलक प्रतिनिधि मंगलाचरण को संभालने के लिए अधिक आईएल कोड का उत्पादन करता है?
टेस्टकोडकर

2
कोई @testCoder, यह प्रतिबिंब का उपयोग करेंगे
मार्क Gravell

@MarcGravell जब मैं इस तरीके से कोशिश कर रहा हूं, जो घटना को बढ़ा रहा है, तो मुझे पहली विधि कॉल प्राप्त हो रही है जिसमें लगभग 0,7766 एमएस है, लेकिन दूसरा लगभग 0,0568 एमएस ले रहा है। जब पहला इनवोक होता है तो इसे डायनामिक इनवोक या इसके विपरीत से अधिक समय लगता है। जब मैंने 1 लूप के साथ आपके उदाहरण की कोशिश की और एमएस को देखा Invoke: 0,0478ms, DynamicInvoke: 0,053ms। आप उनकी तुलना 1 कॉल से अधिक क्यों कर रहे हैं? और पहले वाले को फ़ंक्शन की दूसरी कॉल से अधिक समय क्यों लगता है?
uzay95

4
@ uzay95 विधि के लिए पहला कॉल JIT संकलन CLR द्वारा जगह लेता है - यह प्रक्रिया शुरू होने के बाद पहली बार इसे शुरू करने पर किसी भी विधि पर लागू होता है। इस तरह के परिदृश्य में, आप तीन चीजों में से एक कर सकते हैं: (1) विधि को कई बार चलाएं ताकि पहली कॉल के लिए लगने वाला समय अंतिम परिणाम में नगण्य हो जाए, (2) आपके बाद तक माप शुरू न करें एक बार विधि कहा जाता है, या (3) ngen.exe (ओवरकिल) का उपयोग करें। यह पोस्ट इसे काफी अच्छी तरह से समझाती है ... stackoverflow.com/questions/4446203/…
क्वांटा

@ marc-gravell आपको डायनामिकइनवोक को पास करने के लिए एक सरणी बनाने की आवश्यकता नहीं है क्योंकि यह विधि हस्ताक्षर है जो args पैरामीटर के लिए params कीवर्ड बताता है ।
zodo
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.