2012-05-13 12 views
5

मैं हाल ही में सी # 5.0 एसिंक विधियों का उपयोग करना चाहता हूं, हालांकि कुछ विशिष्ट तरीका।क्या सी # 5.0 में एक ही एसिंक विधि हस्ताक्षर का उपयोग करना संभव है और बाद में यह तय करने में सक्षम हो कि इस विधि को कैसे कार्यान्वित किया जाए

public abstract class SomeBaseProvider : ISomeProvider 
{ 
    public abstract Task<string> Process(SomeParameters parameters);  
} 

public class SomeConcreteProvider1 : SomeBaseProvider 
{ 

    // in this method I want to minimize any overhead to create/run Task 
    // NOTE: I remove here async from method signature, because basically I want to run 
    // method to run in sync! 
    public override Task<string> Process(SomeParameters parameters) { 

     string result = "string which I don't need any async code to get"; 

     return Task.Run(() => result); 
    } 
} 

public class SomeConcreteProvider2 : SomeBaseProvider 
{ 

    // in this method, it's OK for me to use async/await 
    public async override Task<string> Process(SomeParameters parameters) { 

     var data = await new WebClient().DownloadDataTaskAsync(urlToRequest); 

     string result = // ... here we convert data byte[] to string some way 

     return result; 

    } 
} 

अब कैसे मैं async तरीकों का उपयोग करने जा रहा हूँ (आप इस तथ्य मेरे मामले में उपभोक्ता वास्तव में ASP.NET MVC4 एप्लिकेशन ... यह कुछ भी हो सकता है कि उपेक्षा कर सकते हैं):

उदाहरण कोड निम्नलिखित पर विचार करें:

public class SomeAsyncController : AsyncController 
{ 

    public async Task<ActionResult> SomethingAsync(string providerId) 
    { 
     // we just get here one of providers I define above 
     var provider = SomeService.GetProvider(providerId); 

     // we try to execute here Process method in async. 
     // However we might want to actually do it in sync instead, if 
     // provider is actually SomeConcreteProvider1 object. 
     string result = await provider.Process(new SomeParameters(...)); 

     return Content(result); 
    } 
} 

आप 2 कार्यान्वयन है देख सकते हैं, हर एक को अलग ढंग से प्रदर्शन करेंगे: एक मैं async में चलाना चाहते हैं और धागे को ब्लॉक नहीं करती (SomeConcreteProvider2), जबकि दूसरे से मैं सिंक में चलाने के लिए सक्षम होना चाहता हूँ और कोई कार्य ऑब्जेक्ट आदि न बनाएं (जो मैं उपरोक्त कोड में कोड करने में विफल रहता हूं, यानी मैं यहाँ नया कार्य बना रहा हूँ!)।

पहले से ही How would I run an async Task<T> method synchronously? जैसे प्रश्न हैं। हालांकि मैं सिंक में कुछ नहीं चलाना चाहता हूं ... अगर मैं कोड समय (यानी रनटाइम से पहले) पर जानता हूं तो मैं किसी भी ओवरहेड से बचना चाहता हूं कि कुछ विधियों के कार्यान्वयन वास्तव में असिंक नहीं होंगे और किसी भी धागे/I का उपयोग करने की आवश्यकता नहीं होगी/ओ पूर्णता बंदरगाह इत्यादि। यदि आप उपरोक्त कोड की जांच करते हैं, तो यह देखने में आसान है कि कुछ कंक्रीटप्रोवाइडर 1 में उस विधि को मूल रूप से कुछ स्ट्रिंग (एचटीएमएल) का निर्माण किया जाएगा, यह उसी निष्पादन थ्रेड पर बहुत तेज़ी से कर सकता है। हालांकि SomeConcreteProvider2 में एक ही विधि को वेब अनुरोध बनाने, वेब प्रतिक्रिया प्राप्त करने और इसे किसी भी प्रक्रिया की आवश्यकता होगी और मैं अनुरोध समय के दौरान पूरे धागे को अवरुद्ध करने से बचने के लिए Async में कम से कम वेब अनुरोध करना चाहता हूं (वास्तव में लंबे समय से छोड़ दिया जा सकता है)।

तो सवाल यह है कि: विधि को निष्पादित करने का तरीका तय करने में सक्षम होने के लिए मेरे कोड (विभिन्न विधि हस्ताक्षर या विभिन्न कार्यान्वयन, या?) को व्यवस्थित करने के लिए कैसे करें और किसी भी संभावित ओवरहेड से बचें जो उदाहरण के लिए कार्य के कारण होता है। Run (.. ।) कुछ कंक्रीटप्रोवाइडर 1। प्रोसेस विधि में?

अद्यतन 1: स्पष्ट समाधान इस तरह के प्रदाताओं में से प्रत्येक के लिए कुछ स्थिर संपत्ति जोड़ने के लिए उदाहरण के लिए के रूप में (कहते हैं 'isAsyncImplementation') और फिर उस संपत्ति की जाँच कैसे तय करने के लिए (मैं उनमें से कुछ सवाल प्रक्रिया के दौरान लगता है), विधि को चलाने के लिए (प्रतीक्षा करने या नियंत्रक कार्रवाई में इंतजार किए बिना) कुछ ओवरहेड भी है: DI यदि संभव हो तो कुछ बेहतर चाहिए: डी

+0

पीएस इस सवाल के लिए सही शीर्षक बनाना वाकई मुश्किल था। अगर कोई इसे ठीक कर सकता है तो खुशी होगी :) धन्यवाद – Evereq

+0

मेरा मानना ​​है कि बिना किसी इंतजार के एसिंक विधि बनाना कार्य कैशिंग के कारण तेज हो सकता है। – SLaks

+0

@SLaks का मतलब है कि मेरा कोड कुछ कंक्रीटप्रोवाइडर 1 में है। कुछ कार्य कैशिंग के कारण प्रोसेस पहले से ही पर्याप्त है? – Evereq

उत्तर

10

अपने पहले मामले में, मैं लौटने की सिफारिश करेंगे:

Task.FromResult(result) 

जो तैयार पूर्ण कार्य देता है।

http://msdn.microsoft.com/en-us/library/hh194922%28v=vs.110%29.aspx

+0

आह, इसके बारे में पता नहीं - बहुत अच्छा दृष्टिकोण प्रतीत होता है: डी धन्यवाद :) – Evereq

+0

एचएम, ऐसा लगता है जैसे मैं कार्य के साथ टास्क.रुन (() => परिणाम) को प्रतिस्थापित करता हूं। फ़ोरमसेट (परिणाम) कोड संकलन, हालांकि जब मैं वास्तव में नियंत्रक कार्रवाई निष्पादित करता हूं तो यह खाली सामग्री लौटाता है :) Ie कार्य की प्रतीक्षा से संबंधित कुछ मुद्दे हो सकते हैं। FromResult !? उदाहरण के लिए देखें http://social.msdn.microsoft.com/Forums/nl-NL/async/thread/d9146792-1b9a-4807-a42e-29107c281cc4 आदि – Evereq

+3

@EvereQ - MVC4 बीटा में एक बग है जहां यह नहीं है पहले से ही पूरा कार्य लौटाया जा रहा है। अनुशंसित बीटा वर्कअराउंड इस तरह के एसिंक तरीकों के शीर्ष पर एक कार्य.इल्ड जोड़ रहा है, लेकिन कार्य। रून इस उदाहरण में आपके लिए व्यवहार्य कामकाज की तरह लगता है। –

0

आपका डिज़ाइन ठीक दिखता है।

SomeConcreteProvider1 मामले के लिए, आप यह एक Task रिटर्न संगामिति की आवश्यकता के बिना एक TaskCompletionSource

उपयोग कर सकते हैं।

इसके अलावा, उपभोक्ता कोड में, await तब नहीं मिलेगा जब Task पहले ही पूरा हो चुका है। इसे "फास्ट पथ" कहा जाता है और प्रभावी ढंग से विधि को तुल्यकालिक बनाता है।

+0

एचएम, सुनिश्चित नहीं है कि कैसे "आसान" का उपयोग करें TaskCompletionSource यहां ... I.e. आप TaskCompeltionSource वापस करने का मतलब है और क्लाइंट को कोड निष्पादित करने का निर्णय लेते हैं? हालांकि सवाल यह है कि क्लाइंट को कैसे पता चलेगा कि दिए गए प्रदाता के लिए एसिंक या सिंक निष्पादन आवश्यक है यदि आप केवल कार्यसमूह स्रोत ऑब्जेक्ट वापस करते हैं? ;-) – Evereq

+1

आप 'SomeConcreteProvider1.Process'' में 'कार्य पूर्णीकरण स्रोत ' ऑब्जेक्ट बना सकते हैं, परिणाम/रद्दीकरण/अपवाद सेट कर सकते हैं और 'कार्य' संपत्ति वापस कर सकते हैं। यदि आप केवल परिणाम सेट करने जा रहे हैं, तो आप स्पेंडर के रूप में 'टास्क.फ्रॉम रिसेट' का उपयोग कर सकते हैं। किसी भी तरह से, 'कार्य' वापस लौटाकर जो पहले ही पूरा हो चुका है, उपभोक्ता कोड में 'प्रतीक्षा' उपज नहीं करेगा - निष्पादन केवल सिंक्रनाइज़ेशन जारी रहेगा। –

+0

आह, ऐसा लगता है कि मुझे कार्य का इंतजार करने के लिए समस्याएं मिली हैं। किसी कारण से फ्रॉम रिसेट (@spender द्वारा जवाब देने के लिए मेरी टिप्पणी देखें)। हालांकि TaskCompletionSource – Evereq

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

  • कोई संबंधित समस्या नहीं^_^