2012-02-13 4 views
12

मेरे मूल विधि की तरह दिखता है। बाद में मैं निष्पादन आईडी द्वारा परिणाम पूछताछ कर सकता हूं। मुख्य बिंदु नौकरी पूरा होने से पहले निष्पादन आईडी उपलब्ध कराने के लिए है।क्या यह विधि से अधिक जानकारी वापस करने के लिए टीपीएल कार्य से प्राप्त करना ठीक है?</p> <pre><code>string DoSomeWork(); </code></pre> <p>विधि <code>DoSomeWork</code> अन्य धागे पर कुछ काम शुरू होता है और रिटर्न निष्पादन ID (बस यादृच्छिक स्ट्रिंग):

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

Task DoSomeWork(); 

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

क्या होगा यदि मैं वर्ग कि Task वर्ग से निकाले जाते हैं जाएगा पैदा करेगा:

public class ExtendedTask : Task 
{ 
    public string ExecutionID {get; set;} 
} 

यह ठीक लग रहा है करता है? या अन्य विकल्पों का फैसला करना बेहतर है?

पीएस बीसीएल में कुछ कार्य वर्गों से व्युत्पन्न होते हैं।

अद्यतन, लगता है मैं यह स्पष्ट enouthg परिभाषित करने के लिए सक्षम नहीं था। लेकिन नौकरी पूरा होने से पहले मुझे निष्पादन आईडी तक पहुंच की आवश्यकता है और इसलिए मैं Task.Result का उपयोग नहीं कर सकता।

उत्तर

12

मैं व्यक्तिगत रूप से Task<T> का विस्तार नहीं होगा, मैं यह बजाय रचना चाहते। इस तरह आपको किसी भी एपीआई के बारे में चिंता करने की आवश्यकता नहीं है जो केवल Task<T> लौटाता है - आप केवल कार्य को लपेट सकते हैं। आपके पास एक संपत्ति हो सकती है जो अंतर्निहित कार्य का खुलासा करता है, और सी # 5 एसिंक उद्देश्यों के लिए आप अपने स्वयं के प्रकार पर प्रतीक्षाकर्ता पैटर्न लागू कर सकते हैं - लेकिन मुझे लगता है कि अपना खुद का व्युत्पन्न प्रकार बनाना अधिक नुकसान करने के लिए है से बेहतर। हालांकि यह ज्यादातर एक आंत महसूस कर रहा है।

दूसरा विकल्प दूसरे तरीके से काम करना है: Task.AsyncState संपत्ति में अपना अतिरिक्त राज्य स्टोर करें; आखिरकार, यह वही है।इस तरह आप निष्पादन संदर्भ खोने के बिना आसानी से कार्य को आसानी से पास कर सकते हैं, यह तर्कसंगत रूप से इसका हिस्सा है।

+0

'टास्क.एसिंकस्टेट' के लिए धन्यवाद, मुझे इसके बारे में पता नहीं था। मैं केवल चिंतित हूं कि यह क्यों ऑब्जेक्ट करता है? कोई इसे ओवरराइड कर सकता है। –

+1

@ माइक चाली का उद्देश्य IAsyncResult को लागू करने के लिए है, और केवल पढ़ा जाता है। एक बार जब आप अपना काम तैयार करेंगे तो कोई भी इसे आप पर ओवरराइड नहीं कर सकता है। इस सेट को प्राप्त करने के लिए आपको 'एक्शन' के बजाय' एक्शन 'ले जाने वाले रचनाकारों में से एक का उपयोग करके कार्य का निर्माण करने की आवश्यकता है ... –

+0

@ReedCopsey ups, हाँ, आप सही हैं। खैर, फिर भी अच्छा लगता है। –

11

मैं इसके बजाय Task<T> का उपयोग करने की अनुशंसा करता हूं, क्योंकि यह आपको कार्य के परिणाम में अन्य जानकारी को "एम्बेड" करने की अनुमति देता है।

उदाहरण के लिए, अपने मामले में, यह हो सकता है भावना की तरह कुछ है करने के लिए: टिप्पणी के जवाब में

class ExecutionResult 
{ 
    public int ExecutionID { get; set; } 
    public string Result { get; set; } 
    // ... 
} 


public Task<ExecutionResult> DoSomeWork() 
{ 
    return Task.Factory.StartNew(() => 
    { 
      // Replace with real work, etc... 
      return new ExecutionResult { ExecutionID = 0, Result = "Foo" }; 
    }); 
} 

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

आप "से पहले" टास्क डेटा की जरूरत है पूर्ण करता है और अन्य प्रयोजनों के लिए इस का उपयोग करने की, होगा एक वर्ग है कि टास्क और अन्य डेटा शामिल हैं बनाने की सलाह देते हैं यानी कोशिश कर रहे हैं मैं, और यह लौटने:

class ExecutionResult 
{ 
    public int ExecutionID { get; private set; } 
    public Task<string> Result { get; private set; } 
    // ... Add constructor, etc... 
} 


public ExecutionResult DoSomeWork() 
{ 
    var task = Task.Factory.StartNew(() => 
    { 
      // Replace with real work, etc... 
      return "Foo"; 
    }); 

    return new ExecutionResult(1, task); // Make the result from the int + Task<string> 
} 

यह आपको अभी भी आपकी प्रक्रिया के बारे में जानकारी तक पहुंचने देगा, और Task/Task<T>

+0

'कार्य। परिणाम 'उपलब्ध होगा। मुझे पहले इस मूल्य की ज़रूरत है। –

+1

@ माइक चाली ने यह दिखाने के लिए संपादित किया कि मैं इस मामले में कैसे पहुंचूंगा ... –

+0

आपके उत्तर के लिए धन्यवाद। –

1

यदि आप Task या Task<TResult> से विरासत का फैसला करते हैं, आप हताशा कि Action<Object> या Func<Object,TResult> प्रतिनिधि उस कार्य निर्दिष्ट किया जाना चाहिए समय के लिए वास्तविक कार्य प्रदान करता है अपने कार्य व्युत्पन्न सामना कर सकते हैं वस्तु का निर्माण किया गया है, और बाद में बदला नहीं जा सकता है। यह सच है भले ही बेस क्लास कन्स्ट्रक्टर Start() नव निर्मित कार्य नहीं करता है, और वास्तव में इसे तब तक शुरू नहीं किया जा सकता है जब तक कि कभी भी नहीं।

इससे Task-स्थितियों में स्थित श्रेणी का उपयोग करना मुश्किल हो जाता है जहां उदाहरणों को अपने अंतिम कार्य के पूर्ण विवरण से पहले बनाया जाना चाहिए।

एक उदाहरण प्रसिद्ध Task<TResult> एक साझा लक्ष्य पर काम कर नोड्स के एक अनाकार नेटवर्क हो सकता है ऐसी है कि वे एक तदर्थ ढंग से एक-दूसरे के Result गुण का उपयोग। यह गारंटी देने का सबसे आसान तरीका है कि आप नेटवर्क में किसी भी मनमाने ढंग से नोड पर Wait() कर सकते हैं, उनमें से किसी भी को शुरू करने से पहले उन सभी को पूर्व-निर्माण करना है। यह अच्छी तरह से कार्य ग्राफ निर्भरताओं का विश्लेषण करने की समस्या से बचाता है, और रनटाइम कारकों को यह निर्धारित करने की अनुमति देता है कि कब, यदि, और किस क्रम में Result मानों की मांग की जाती है।

समस्या यह है कि, कुछ नोड्स के लिए, आप उस कार्य को प्रदान करने में सक्षम नहीं हो सकते हैं जो निर्माण समय पर कार्य को परिभाषित करता है। यदि आवश्यक लैम्ब्डा फ़ंक्शन बनाने के लिए नेटवर्क में अन्य कार्यों से Result मानों को बंद करने की आवश्यकता है, तो Task<TResult> जो Result प्रदान करता है, हम चाहते हैं कि अभी तक निर्माण नहीं किया गया हो। और यहां तक ​​कि अगर पूर्व निर्माण चरण के दौरान पहले इसका निर्माण किया गया था, तो भी आप Start() पर कॉल नहीं कर सकते हैं क्योंकि यह अन्य नोड्स पर निर्भरता को शामिल कर सकता है। याद रखें, नेटवर्क की पूर्व-निर्माण का पूरा बिंदु इन तरह की जटिलताओं से बचना था।

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

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

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

'टास्क' से पाने के लिए: 'टास्क <TResult>' से पाने के लिए

public abstract class DeferredActionTask : Task 
{ 
    private DeferredActionTask(DeferredActionTask _this) 
     : base(_ => ((Func<DeferredActionTask>)_)().action(), 
       (Func<DeferredActionTask>)(() => _this)) 
    { 
     _this = this; 
    } 
    protected DeferredActionTask() : this(null) { } 

    protected abstract void action(); 
}; 

:

public abstract class DeferredFunctionTask<TResult> : Task<TResult> 
{ 
    private DeferredFunctionTask(DeferredFunctionTask<TResult> _this) 
     : base(_ => ((Func<DeferredFunctionTask<TResult>>)_)().function(), 
       (Func<DeferredFunctionTask<TResult>>)(() => _this)) 
    { 
     _this = this; 
    } 
    protected DeferredFunctionTask() : this(null) { } 

    protected abstract TResult function(); 
}; 

[संपादित करें: सरलीकृत]

ये सरलीकृत संस्करण व्युत्पन्न उदाहरणों 'कार्रवाई या फ़ंक्शन विधि पर सीधे बंद करके बाहरी बंद करने को कम करते हैं। यदि आप इसका उपयोग करना चाहते हैं तो यह बेस क्लास में AsyncState को भी मुक्त करता है। यह शायद ही जरूरी लगता है क्योंकि अब आपकी अपनी पूरी व्युत्पन्न कक्षा है; तदनुसार, AsyncState कार्य समारोह में पारित नहीं किया गया है। यदि आपको इसकी ज़रूरत है, तो आप हमेशा बेस क्लास पर संपत्ति से इसे पकड़ सकते हैं। अंत में, विभिन्न वैकल्पिक पैरामीटर अब Task बेस क्लास के माध्यम से पारित किए जा सकते हैं।

'टास्क' से पाने के लिए:

public abstract class DeferredActionTask : Task 
{ 
    private DeferredActionTask(Action _a, Object state, CancellationToken ct, TaskCreationOptions opts) 
     : base(_ => _a(), state, ct, opts) 
    { 
     _a = this.action; 
    } 

    protected DeferredActionTask(
      Object state = null, 
      CancellationToken ct = default(CancellationToken), 
      TaskCreationOptions opts = TaskCreationOptions.None) 
     : this(default(Action), state, ct, opts) 
    { 
    } 

    protected abstract void action(); 
}; 

'टास्क <TResult>' से पाने के लिए: एक async की

public abstract class DeferredFunctionTask<TResult> : Task<TResult> 
{ 
    private DeferredFunctionTask(Func<TResult> _f, Object state, CancellationToken ct, TaskCreationOptions opts) 
     : base(_ => _f(), state, ct, opts) 
    { 
     _f = this.function; 
    } 

    protected DeferredFunctionTask(
      Object state = null, 
      CancellationToken ct = default(CancellationToken), 
      TaskCreationOptions opts = TaskCreationOptions.None) 
     : this(default(Func<TResult>), state, ct, opts) 
    { 
    } 

    protected abstract TResult function(); 
}; 
0
private async DeferredFunctionTask<int> WaitForStart(CancellationTokenSource c, string serviceName) 
    { 


     var t = await Task.Run<int>(() => 
     { 
      int ret = 0; 
      for (int i = 0; i < 500000000; i++) 
      { 


       //ret += i; 
       //if (i % 100000 == 0) 
       // Console.WriteLine(i); 

       if (c.IsCancellationRequested) 
       { 
        return ret; 
       } 
      } 

      return ret; 

     }); 


     return t; 
    } 

त्रुटि CS1983 वापसी प्रकार विधि शून्य, कार्य या कार्य

होना चाहिए नौकरी पूरा होने के बाद
संबंधित मुद्दे