14

पर उपयोग करने वाले विधियों को प्रतिस्थापित करना मेरे प्रश्न कई हैं। चूंकि मैंने देखा। नेट 4.5, मैं बहुत प्रभावित था। दुर्भाग्य से मेरी सभी परियोजनाएं .NET 4.0 हैं और मैं माइग्रेट करने के बारे में सोच नहीं रहा हूं। तो मैं अपना कोड सरल बनाना चाहता हूं।पृष्ठभूमि कार्यकर्ता को async/tpl (.NET 4.0)

वर्तमान में, मेरी कोड है कि आमतौर पर पर्याप्त समय लेने के लिए स्क्रीन को स्थिर करने के अधिकांश, मैं निम्न कार्य करें:

BackgroundWorker bd = new BackgroundWorker(); 
bd.DoWork += (a, r) => 
    { 
     r.Result = ProcessMethod(r.Argument); 
    }; 
bd.RunWorkerCompleted += (a, r) => 
    { 
     UpdateView(r.Result); 
    }; 

bd.RunWorkerAsync(args); 

ईमानदारी से, मैं इसके बारे में थक गया हूँ। और तर्कसंगत जटिल उपयोगकर्ता इंटरैक्शन होने पर यह एक बड़ी समस्या बन जाती है।

मुझे आश्चर्य है, इस तर्क को सरल कैसे करें? (याद रखें कि मैं साथ हूं। नेट 4.0) मैंने Google द्वारा कुछ चीजें देखी हैं, लेकिन मुझे कुछ भी आसान नहीं है और मेरी जरूरतों के लिए उपयुक्त है।

मैं इस समाधान नीचे सोचा:

var foo = args as Foo; 
var result = AsyncHelper.CustomInvoke<Foo>(ProcessMethod, foo); 
UpdateView(result); 

public static class AsyncHelper 
{ 
    public static T CustomInvoke<T>(Func<T, T> func, T param) where T : class 
    { 
     T result = null; 
     DispatcherFrame frame = new DispatcherFrame(); 
     Task.Factory.StartNew(() => 
     { 
      result = func(param); 
      frame.Continue = false; 
     }); 

     Dispatcher.PushFrame(frame); 

     return result; 
    } 
} 

मुझे यकीन है कि प्रभाव डिस्पैचर फ्रेम से छेड़छाड़ पर है के बारे में नहीं हूँ। लेकिन मुझे पता है कि यह बहुत अच्छा काम करेगा, उदाहरण के लिए, मैं स्क्रीन को फ्रीज करने के बावजूद नियंत्रण की सभी घटनाओं में इसका उपयोग कर सकता हूं। सामान्य प्रकार, कॉन्वर्सिस, contravariance के बारे में मेरा ज्ञान सीमित है, शायद इस कोड में सुधार किया जा सकता है।

मैंने Task.Factory.StartNew और Dispatcher.Invoke का उपयोग करके अन्य चीजों के बारे में सोचा, लेकिन ऐसा कुछ भी नहीं जो दिलचस्प और उपयोग करने में आसान लगता है। क्या कोई मुझे कुछ प्रकाश दे सकता है?

उत्तर

15

आपको केवल कार्य समांतर लाइब्रेरी (टीपीएल) का उपयोग करना चाहिए। कुंजी यूआई को अपडेट करने वाली किसी भी निरंतरता के लिए वर्तमान SynchronizationContext के लिए TaskScheduler निर्दिष्ट कर रही है। उदाहरण के लिए:

Task.Factory.StartNew(() => 
{ 
    return ProcessMethod(yourArgument); 
}) 
.ContinueWith(antecedent => 
{ 
    UpdateView(antecedent.Result); 
}, 
TaskScheduler.FromCurrentSynchronizationContext()); 
कुछ अपवाद हैंडलिंग से

एक तरफ जब पूर्ववर्ती के Result प्रॉपर्टी एक्सेस, वह सब वहां भी यह है है। FromCurrentSynchronizationContext() का उपयोग करके परिवेश सिंक्रनाइज़ेशन कॉन्टेक्स्ट जो WPF (यानी डिस्पैचर सिंक्रनाइज़ेशन कॉन्टेक्स्ट) से आता है, निरंतरता निष्पादित करने के लिए उपयोग किया जाएगा। यह Dispatcher.[Begin]Invoke पर कॉल करने जैसा ही है, लेकिन आप इसे पूरी तरह से सारित कर रहे हैं।

आप, यहाँ तक कि "स्वच्छ" पाने के लिए यदि आप ProcessMethod को नियंत्रित मैं वास्तव में है कि एक Task वापस जाने के लिए फिर से लिखने और इसे ही कैसे कि काता जाता है (अभी भी आंतरिक StartNew उपयोग कर सकते हैं) दिया जाएगा करना चाहता है तो। इस तरह आप कॉलर को एसिंक निष्पादन निर्णयों से अमूर्त करते हैं जो ProcessMethod अपने आप बनाना चाहते हैं और इसके बजाय उन्हें केवल परिणाम की प्रतीक्षा करने के लिए निरंतरता पर चेन करने की चिंता करनी होगी।

अद्यतन 5/22/2013

ऐसा लगता है .NET 4.5 के आगमन और सी # में async भाषा समर्थन के साथ इस निर्धारित तकनीक पुरानी हो चुकी है और आप बस उन सुविधाओं पर निर्भर निष्पादित करने के लिए कर सकते हैं कि await Task.Run का उपयोग करके एक विशिष्ट कार्य और उसके बाद निष्पादन स्वचालित रूप से डिस्पैचर थ्रेड पर स्वचालित रूप से होगा। तो इस तरह कुछ:

MyResultType processingResult = await Task.Run(() => 
{ 
    return ProcessMethod(yourArgument); 
}); 

UpdateView(processingResult); 
+0

मेरे कोड को सरल बनाने के लिए एक अच्छा विकल्प प्रतीत होता है, मैं पहले से ही कल्पना कर सकता हूं कि इसका उपयोग कैसे किया जाए। हालांकि, क्यू समाधान नहीं होगा कि मैं एक ही विधि निष्पादन में जारी रख सकता हूं? –

+0

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

1

कोड को encapsulating के बारे में कैसे एक पुन: प्रयोज्य घटक में हमेशा एक ही है? आप एक फ्रीजबल बना सकते हैं जो आईसीओएमएंड लागू करता है, टाइप DoWorkEventHandler और एक परिणाम संपत्ति की संपत्ति का खुलासा करता है। आईसीओएमएंड पर।निष्पादित, यह एक पृष्ठभूमिवर्कर बनायेगा और DoWorkEventHandler के इवेंट हैंडलर के रूप में डूवॉर्क्स और पूर्ण के लिए प्रतिनिधियों को तार देगा, और इस तरह से संभालने के तरीके को पूरा करने के तरीके को पूरा करने के तरीके से पूरा हो जाएगा।

आप XAML में घटक कॉन्फ़िगर करना चाहते हैं, एक कनवर्टर का उपयोग कर ViewModel पर एक विधि (मुझे लगता है कि आप एक मिल गया है) करने के लिए DoWorkEventHandler संपत्ति के लिए बाध्य है, और घटक के परिणाम संपत्ति के लिए अपने दृश्य बाध्य करने के लिए, तो यह हो जाता है परिणाम बदलते समय स्वचालित रूप से अपडेट किया जाता है।

इस समाधान के फायदे हैं: यह पुन: प्रयोज्य है, और यह केवल एक्सएएमएल के साथ काम करता है, इसलिए पृष्ठभूमि व्यूकर्स को संभालने के लिए आपके व्यूमोडेल में कोई और गोंद कोड नहीं है। यदि आपको प्रगति की रिपोर्ट करने के लिए अपनी पृष्ठभूमि प्रक्रिया की आवश्यकता नहीं है, तो यह भी अनजान हो सकता है कि यह पृष्ठभूमि थ्रेड पर चलता है, इसलिए आप XAML में निर्णय ले सकते हैं कि आप एक विधि को सिंक्रनाइज़ या असीमित रूप से कॉल करना चाहते हैं।

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