Task.Factory.StartNew: Task Factory Class के StartNew() Method का प्रयोग करके हम किसी Task को Create करते ही उसे Start भी कर सकते हैं। यानी हमें इन दोनों कामों को पिछले उदाहरणों के अनुसार अलग-अलग करने की जरूरत नहीं है। यानी TaskFactory एक ऐसी Class है जो हमारे Task Creation व Management के काम को काफी आसान बना देता है।
Default TaskFactory को Task द्वारा Provided Factory नाम की Read-Only Property के माध्यम से Obtain किया जा सकता है। इस Property का प्रयोग करके हम किसी भी TaskFactory Method को Invoke कर सकते हैं।
StartNew() Method को नया Task Create व Execute करने के लिए कई तरीकों से Use किया जा सकता है, जिनमें से एक तरीका निम्नानुसार है और बाकी तरीकों की जानकारी प्राप्त करने के लिए हम Visual Studio के Object Browser Utility का प्रयोग कर सकते हैं:
public Task StartNew(Action action)
इस Syntax में action उस Code का Entry Point यानी वह Target Method होता है, जिसे Task के रूप में Execute करना होता है, जबकि यदि हम चाहें तो उस Task को Action Delegate Object में Store करके उस Delegate Object को भी इस StartNew() Method में Parameter की तरह Specify कर सकते हैं। इस Method को हम निम्नानुसार तरीके से Use कर सकते हैं:
Task tsk = Task.Factory.StartNew(MyTask)
यदि हम इस TaskFactory Method को Use करते हुए अपने पिछले Program को Recreate करना चाहें, तो हमारा Program कुछ निम्नानुसार बनेगा:
File Name: UsingTaskFactory-StartNewMethod.cs using System; using System.Threading; using System.Threading.Tasks; namespace CSharpMultiThreading { class DemoTask { // A method to be run as a task. static void MyTask() { Console.WriteLine("MyTask() starting"); for (int count = 0; count < 10; count++) { Thread.Sleep(500); Console.WriteLine("In MyTask(), count is " + count); } Console.WriteLine("MyTask terminating"); } static void Main() { Console.WriteLine("Main thread starting."); // Construct and Run a task. Task tsk = Task.Factory.StartNew(MyTask); // Keep Main() alive until MyTask() finishes. tsk.Wait(); Console.WriteLine("Main thread ending."); } } } Output: Main thread starting. MyTask() starting In MyTask(), count is 0 In MyTask(), count is 1 In MyTask(), count is 2 In MyTask(), count is 3 In MyTask(), count is 4 In MyTask(), count is 5 In MyTask(), count is 6 In MyTask(), count is 7 In MyTask(), count is 8 In MyTask(), count is 9 MyTask terminating Main thread ending.
जैसाकि इस Program का Output देखकर हम समझ सकते हैं कि इस Program को Run करने पर भी हमें वही Output प्राप्त हो रहा है, जो पिछले Program का प्राप्त हो रहा था। लेकिन इस Program में हमने StartNew() Method का प्रयोग किया है, जो कि पिछले Program में Use किए गए Task Method की तुलना में ज्यादा Efficient होता है।
Using Lambda Expression for New Task
हालांकि हम किसी Normal Method को Task की तरह Specify कर सकते हैं, जैसाकि पिछले विभिन्न Programs में किया है। लेकिन ये भी सम्भव है कि हम किसी Anonymous Method या Lambda Expression को भी Task के रूप में Specify कर सकते हैं। Anonymous Method या Lambda Expression तब महत्वपूर्ण होते हैं, जब हमें किसी Single Use Task को Create व Run करना होता है। यदि हम हमारे पिछले Program के Task को Lambda Expression की तरह Modify करना चाहें, तो हमारा Modified Program कुछ निम्नानुसार बन सकता है:
File Name: TaskAsLambdaExpression.cs using System; using System.Threading; using System.Threading.Tasks; namespace CSharpMultiThreading { class DemoTask { static void Main() { Console.WriteLine("Main thread starting."); // Construct and Run a task. Task tsk = Task.Factory.StartNew( //Lambda Expression of MyTask () => { Console.WriteLine("MyTask() starting"); for (int count = 0; count < 10; count++) { Thread.Sleep(500); Console.WriteLine("In MyTask(), count is " + count); } Console.WriteLine("MyTask terminating"); } ); // Keep Main() alive until MyTask() finishes. tsk.Wait(); Console.WriteLine("Main thread ending."); } } } Output: Main thread starting. MyTask() starting In MyTask(), count is 0 In MyTask(), count is 1 In MyTask(), count is 2 In MyTask(), count is 3 In MyTask(), count is 4 In MyTask(), count is 5 In MyTask(), count is 6 In MyTask(), count is 7 In MyTask(), count is 8 In MyTask(), count is 9 MyTask terminating Main thread ending.
Creating Task Continuation
TPL की एक मुख्य विशेषता ये है कि ये Task Continuation Create कर सकता है। Continuation एक ऐसी प्रक्रिया होती है, जिसमें कोई एक Task जब Finish हो जाता है, तब Automatically दूसरा Task Begin हो जाता है। Continuation Create करने का एक तरीका ये है कि हम ContinueWith() Method को Use करें जिसे निम्नानुसार Define किया गया है:
public Task ContinueWith(Action<Task> continuationAction)
यहां continuationAction उस Task को Specify करता है, जो उस समय Run होगा जब Invoking Task Complete हो जाएगा। ये Delegate Task Type का एक Parameter Accept करता है, जो कि निम्नानुसार Defined Action Delegate का एक और Version है:
public delegate void Action<in T>(T obj)
यदि हम Continuation के आधार पर अपने पिछले Program को Modify करें, तो हमारा Program कुछ निम्नानुसार हो सकता है:
File Name: TaskContinuation.cs using System; using System.Threading; using System.Threading.Tasks; namespace CSharpMultiThreading { class DemoTask { // A method to be run as a task. static void MyTask() { Console.WriteLine("MyTask() starting"); for (int count = 0; count < 5; count++) { Thread.Sleep(500); Console.WriteLine("In MyTask(), count is " + count); } Console.WriteLine("MyTask terminating"); } // A method to be run as a continuation. static void ContTask(Task t) { Console.WriteLine("Continuation starting"); for (int count = 0; count < 5; count++) { Thread.Sleep(500); Console.WriteLine("Continuation count is " + count); } Console.WriteLine("Continuation terminating"); } static void Main() { Console.WriteLine("Main thread starting."); // Construct and Run a task. Task tsk = Task.Factory.StartNew(MyTask); Task taskCont = tsk.ContinueWith(ContTask); // Keep Main() alive until MyTask() finishes. tsk.Wait(); taskCont.Wait(); // Dispose all tasks. tsk.Dispose(); taskCont.Dispose(); Console.WriteLine("Main thread ending."); } } } Output: Main thread starting. MyTask() starting In MyTask(), count is 0 In MyTask(), count is 1 In MyTask(), count is 2 In MyTask(), count is 3 In MyTask(), count is 4 MyTask terminating Continuation starting Continuation count is 0 Continuation count is 1 Continuation count is 2 Continuation count is 3 Continuation count is 4 Continuation terminating Main thread ending.
जैसाकि हम इस Program के Output से ही समझ सकते हैं कि ये Program पहले Task को पूरा करने के Just बाद कौनसा अगला Task पूरा करना है, इस बात को निम्नानुसार Statement के माध्यम से निश्चित करता है:
Task taskCont = tsk.ContinueWith(ContTask);
परिणामस्वरूप जैसे ही पहला Task पूरा हो जाता है, C# Compiler Automatically दूसरे Task को Continue कर देता है और हमें उपरोक्तानुसार Output प्राप्त होता है।
Task Type द्वारा Provided ContinueWith() Method के अलावा TaskFactory Type ContinueWhenAny() व ContinueWhenAll() Methods को भी Support करता है, जो कि ContinueWith() Method की तरह ही Continuation Methods को Parameter की तरह Use करते हैं।
Returning Task Value
हम किसी Task द्वारा किसी Value को Return भी करवा सकते हैं। दो कारणों से ये एक बहुत ही महत्वपूर्ण Feature है। हम किसी Task द्वारा कोई Computation कर सकते हैं और हम जो Computation करते हैं, वह Parallel Computation होता है तथा Calling Process तब तक के लिए Block हो जाता है, जब तक कि Task द्वारा Generated Computed Result Use होने के लिए Ready नहीं हो जाता। यानी हमें किसी Special Synchronization करने की जरूरत नहीं है, जैसाकि कि हमने Threads को Use करने के दौरान किया था।
Task द्वारा Result Return करने के लिए हम Task के एक Generic Form को Use करते हैं, जो कि Task<TResult> होता है। इस Type के लिए निम्नानुसार दो Constructors Defined हैं:
public Task(Func<TResult> function)
public Task(Func<Object, TResult> function, Object state)
यहां function वह Delegate है, जो Run होता है। Func का प्रयोग हमने इसलिए किया है क्योंकि ये Delegate Result Return करता है, जबकि Action Delegate Result Return नहीं करता।
पहला Constructor एक ऐसा Task Method Parameter के रूप में Accept करता है, जो कि कोई Argument Accept नहीं करता। जबकि दूसरा Constructor Object Type का एक Argument Accept करने वाले Task Method को Parameter के रूप में Accept करता है। इनके अलावा और भी Constructors हैं, जिन्हें Use किया जा सकता है।
इसी तरह से TaskFactory<TResult> द्वारा Provided StartNew() Method के भी और Version हैं जो किसी Task से Generate होने वाले Result को Return करते हैं। जिनमें से दो Versions निम्नानुसार हैं:
public Task<TResult> StartNew(Func<TResult> function)
public Task<TResult> StartNew(Func<Object,TResult> function, Object state)
Task द्वारा जो भी Value Return होती है, उसे Task की Result Property द्वारा Retrieve किया जाता है, जिसे निम्नानुसार Define किया गया है:
public TResult Result { get; internal set; }
क्योंकि set Accessor Internal Access Mode में है, इसलिए ये Property अन्य External Codes के लिए Read-Only Property होती है। जबकि get Accessor तब तक Result Return नहीं करता जब तक कि Task द्वारा Result Generate नहीं कर दिया जाता। इसलिए जब तक Task द्वारा Result Generate नहीं कर दिया जाताए तब तक Calling Code Blocked रहता है।
File Name: TaskReturingValue.cs using System; using System.Threading; using System.Threading.Tasks; namespace CSharpMultiThreading { class DemoTask { // A trivial method that returns a result and takes no arguments. static bool MyTask() { return true; } // This method returns the summation of a positive integer which is passed to it. static int SumIt(object v) { int x = (int)v; int sum = 0; for (; x > 0; x--) sum += x; return sum; } static void Main() { Console.WriteLine("Main thread starting."); // Construct the first task. Task<bool> tsk = Task<bool>.Factory.StartNew(MyTask); Console.WriteLine("After running MyTask. The result is " + tsk.Result); // Construct the second task. Task<int> tsk2 = Task<int>.Factory.StartNew(SumIt, 3); Console.WriteLine("After running SumIt. The result is " + tsk2.Result); tsk.Dispose(); tsk2.Dispose(); Console.WriteLine("Main thread ending."); } } } Output: Main thread starting. After running MyTask. The result is True After running SumIt. The result is 6 Main thread ending.
इस Program में MyTask() नाम का Method एक Boolean Value Return कर रहा है जबकि SumIt() नाम का Method एक Computed Value Return कर रहा है।
जब इस Program का Main() Method Execute होता है, तो सबसे पहले निम्नानुसार Statement द्वारा एक Task Create करता है जो कि एक Boolean Value Return करता है और इस Task के Complete होने के बाद जो Result Generate होता है, उसे tsk Object की Result Property द्वारा Retrieve करके Output Consol में Display कर लिया जाता है:
Task<bool> tsk = Task<bool>.Factory.StartNew(MyTask);
Console.WriteLine(“After running MyTask. The result is ” + tsk.Result);
फिर निम्नानुसार अगला Statement Pair Execute होता है:
Task<int> tsk2 = Task<int>.Factory.StartNew(SumIt, 3);
Console.WriteLine(“After running SumIt. The result is ” + tsk2.Result);
जो Create होने वाले Task के SumIt() Method में मान 3 Argument के रूप में Pass करता है और Task को Start करता है। Task के Start होते ही निम्नानुसार SumIt() Method Execute होता है:
static int SumIt(object v) { int x = (int)v; int sum = 0; for (; x > 0; x--) sum += x; return sum; }
और Argument के रूप में आने वाले मान 3 तक का जोड करके Return कर देता है। ये Returned मान task2 Task Object की Result Property में Store हो जाता है, जिसे अगले Statement द्वारा Output में Display करवा दिया जाता है।
हम देख सकते हैं कि इस Program में हमने कहीं पर भी Calling Thread में Wait() या Thread.Sleep() Statement का प्रयोग नहीं किया है, क्योंकि Calling Method स्वयं ही तब तक Wait करता है जब तक कि Task द्वारा Generated Result Return नहीं हो जाता।
ये Article इस वेबसाईट पर Selling हेतु उपलब्ध EBook C#.NET in Hindi से लिया गया है। इसलिए यदि ये Article आपके लिए उपयोगी रहा, तो निश्चित रूप से ये पुस्तक भी आपके लिए काफी उपयोगी साबित होगी।
C#.NET in Hindi | Page:908 | Format: PDF