C# BeginInvoke

C# BeginInvoke: जैसाकि हम जानते हैं कि Delegates एक Type-Safe Object Oriented Function Pointers हैं। जब हम कोई .NET Delegate Type Define करते हैं, तो C# Compiler एक Sealed Class Create करता है और उसे System.MulticastDelegate Type से Derive करता है, जो कि स्वयं System.Delegate Type से Derived है।

ये Base Classes हर Delegate को ये क्षमता प्रदान करते हैं कि वे विभिन्न प्रकार के Methods के Addresses की एक List (Invocation List) Maintain कर सकते हैं, जिन्हें बाद में जरूरत के अनुसार Callback की तरह Invoke किया जा सकता है। जैसे:

public delegate int Addition(int x, int y);

इस Definition के आधार पर Addition किसी भी ऐसे Method को Point कर सकता है, जो कि दो Integer Type के Parameters Accept करता है। जब हम इस Definition वाले Program को Compile करते हैं, तो इस Definition के आधार पर .NET Platform स्वयं ही Internally एक पूरी Sealed Class Define करता है, जो कि Delegate के Declaration के आधार पर Dynamically Generate होती है। इसलिए यदि हम हमारे उपरोक्त Declaration के आधार पर बनने वाली Class को देखें, तो वह कुछ निम्नानुसार Create होती है:

C# BeginInvoke - Hindi

इस Class में Invoke() Method उन Methods को Invoke करने का काम करता है, जिन्हें Delegate Object की Invocation List में Synchronous Manner में Maintain किया गया है। इसलिए Calling Thread जो कि सामान्‍यत: किसी Application का Primary Thread होता है, को तब तक Wait करने के लिए Force किया जाता है जब तक कि Delegate की Invocation List के सभी Methods Invoke नहीं हो जाते।

साथ ही C# में Invoke() Method को Directly Call नहीं किया जाता। बल्कि वह उस समय Internally Indirectly Invoke होता है, जब हम Delegate Object की Invocation List में Stored सभी Callback Methods को Invoke करने के लिए Delegate Object को Method की तरह Parenthesis Pair के साथ Specify करते हैं।

इस प्रक्रिया को बेहतर तरीके से समझने के लिए हम निम्नानुसार एक Delegate Based Program Create कर सकते हैं, जो कि Add() नाम के Method को Synchronous यानी Blocking Manner में Invoke करता है:

File Name: UnloadingCustomAppDomain.cs
using System;
using System.Threading;

namespace CSharpMultiThreading
{
  public delegate int Addition(int x, int y);

  class Program
  {
      static void Main(string[] args)
      {
       // Print out the ID of the executing thread.
      Console.WriteLine("Main() invoked on thread {0}.",Thread.CurrentThread.ManagedThreadId);

      // Invoke Add() in a synchronous manner.
      Addition b = new Addition(Add);

      // Could also write b.Invoke(10, 10);
      int answer = b(10, 10);

      // These lines will not execute until the Add() method has completed.
      Console.WriteLine("Doing more work in Main()!");
      Console.WriteLine("10 + 10 is {0}.", answer);
      }

      static int Add(int x, int y)
      {
       // Print out the ID of the executing thread.
       Console.WriteLine("Add() invoked on thread {0}.", Thread.CurrentThread.ManagedThreadId);

       // Pause to simulate a lengthy operation.
       Thread.Sleep(5000);
       return x + y;
       }
    }
}

// Output:
   Main() invoked on thread 1.
   Add() invoked on thread 1.
   Doing more work in Main()!
   10 + 10 is 20.

इस Program में हमने Add() नाम के Method में Thread.Sleep() नाम के Static Method को Invoke किया है, ताकि ;ह Method अपनी Current State पर 5000 Milliseconds यानी 5 Seconds के लिए Suspend हो जाए और हमें ऐसा महसूस हो कि Add() Method में कोई बहुत Lengthy काम कर रहा है, जिसे पूरा होने में समय लगता है।

चूंकि इस Program के Main() Method में हमने Add() Method को एक Synchronous Manner में Invoke किया है। इसलिए जब तक Add() Method अपना काम पूरी तरह से Execute नहीं हो जाताए तब तक Main() Method Result Print नहीं करता।

इस Program में दूसरी Note करने वाली बात ये है कि Main() Method Current Thread का Reference प्राप्त करने के लिए निम्नानुसार Statement के माध्‍यम से Thread.CurrentThread Property को Use कर रहा है:

Console.WriteLine(“Main() invoked on thread {0}.”, Thread.CurrentThread.ManagedThreadId);

और इसी Logic को Add() Method भी निम्नानुसार Statement के माध्‍यम से Implement कर रहा है:

Console.WriteLine(“Add() invoked on thread {0}.”, Thread.CurrentThread.ManagedThreadId);

परिणामस्वरूप हमें जो Output प्राप्त होता है, उसमें हम देख सकते हैं कि दोनों ही Methods को Primary Thread द्वारा ही Invoke किया जा रहा है। यानी हमारा Current Program एक Single-Threaded Application Program ही है, जिसके विभिन्न Methods Synchronous तरीके से यानी One by One Execute होते हैं और जब तक पहला Method पूरी तरह से Execute नहीं हो जाताए तब तक दूसरा Method Execute नहीं होता।

हालांकि बिना किसी परेशानी के किसी Multi-Threaded Application में भी विभिन्न Methods को Synchronous तरीके से Call कर सकते हैं, लेकिन .NET Delegate को इस तरह से Instruct किया जा सकता है कि वह इन Methods को Asynchronous तरीके से Call कर सके। कैसे ?

जैसाकि हम समझ सकते हैं कि कुछ Programming Operations हमेंशा किसी दूसरे प्रकार के Programming Operation की तुलना में ज्यादा समय लेते हैं। उदाहरण के लिए किसी File को Print करने में जितना समय लगता है, वह हमेंशा किसी दूसरे Program को Open करने से बहुत ज्यादा होता है।

इसी बात को यदि हम हमारे पिछले उदाहरण के आधार पर समझें, तो Add() Method को पूरी तरह से Execute होने में 5 Seconds से ज्यादा का समय लगता है, जबकि Main() Method को Execute होने में काफी कम समय लगता है।

जिस तरह से हमारा पिछला उदाहरण Program एक Single-Threaded Program की तरह Behave कर रहा है, उसी तरह से यदि मानलो कि हम कोई Single-Threaded Application बनाते हैं, जो कि किसी Remote Object के किसी Method को Invoke करता है और वह Method Database पर कोई Query Fire करके Result Generate करता है, जिससे Database से बहुत सारा Data Return होता है और उस Return  होने वाले Data को एक External File में Store किया जाता है।

जब ये Operations Perform हो रहे होते हैं, उस समय हमें ऐसा महसूस होता है कि हमारा Application Hang हो गया है, क्योंकि जब तक Remotely Invoke किया गया Method सभी काम Perform नहीं कर लेताए यानी जब तक Database पर Query Fire नहीं हो जाती और सभी Returned Results को एक External File के रूप में Store नहीं कर लिया जाताए तब तक वह Remote Method Finish नहीं होता और जब तक वह Remote Method पूरी तरह से Complete होकर Finish नहीं होताए तब तक हमारा Single-Threaded Application Hanged या Suspended स्थिति में रहता है। क्योंकि हमारा Single-Threaded Application विभिन्न Methods को Synchronous तरीके से One by One Invoke करता है।

इसलिए अब सवाल ये है कि हम किस तरह से किसी Delegate को इस बात का Instruction दे सकते हैं कि वह किसी Method को किसी Separate Execution Thread में Invoke करे] ताकि विभिन्न Methods समान Thread में Invoke होकर Synchronous तरीके से Execute न हों बल्कि अलग-अलग Threads में Invoke होकर समान समय पर समानान्तर रूप से अलग-अलग Execute हों। ताकि हमारा Program तब तक Hanged स्थिति में Suspended न रहे जब तक कि कोई Method Synchronous तरीके से पूरी तरह से Execute होकर Finish न हो जाए।

.NET Framework के Delegate Type की विशेषता ये है कि हमें Delegate Type को इस बात का Instruction देने की जरूरत ही नहीं है। बल्कि .NET Delegate पहले से ही इस स्थिति के प्रति समझदार है और ऐसी स्थिति होने पर वह स्वयं ही विभिन्न Methods को अलग-अलग Threads में Invoke करता है।

यहां तक कि .NET के Latest Platform के अनुसार अब हमें Multi-Threaded .NET Application Create करने के लिए System.Threading Namespace को Detail से समझने की जरूरत ही नहीं है। बल्कि हम बडी ही आसानी से बिना Detailed Threading Knowledge के भी Multi-Threaded Applications Create कर सकते हैं। कैसे\

C# BeginInvoke() and EndInvoke() Methods

जब C# Compiler delegate Keyword को Process करता है, तो C# Compiler Automatically Generate होने वाली Class में BeginInvoke() EndInvoke() नाम के दो Methods को Define कर देता है, जैसाकि Addition() नाम के Delegate के लिए निम्न Code में दर्शाया गया है:

	public sealed class Addition : System.MulticastDelegate
	{
		. . .

		public IAsyncResult BeginInvoke( int x, int y, AsyncCallback cb, object state);
		public int EndInvoke( IAsyncResult result);
	}

इस Code Segment के अनुसार BeginInvoke() Method में पहले दो Parameters वही हैं, जो कि Delegate Declare करते समय हम अपनी जरूरत के अनुसार Delegate द्वारा Invoke होने वाले Methods के Signature को निश्चित करने के लिए Specify करते हैं। जबकि अन्तिम दोनों Parameters हमेंशा System.AsyncCallback System.Object Type के होते हैं। इन दोनों Parameters के बारे में हम आगे विस्तार से जानेंगे, लेकिन फिलहाल हम इन्हें null Assign कर रहे हैं।

साथ ही EndInvoke() Method हमेंशा एक Integer Value return करता है, जो कि Addition() नाम के Delegate के Return Type पर आधारित होता है। जबकि ये Method Parameter के रूप में एक IAsyncResult Type का Argument Accept करता है।

System.IAsyncResult Interface

BeginInvoke() Method हमेंशा एक ऐसा Object Return करता है जिसमें IAsyncResult नाम के Interface को Implement किया गया होता है, जबकि EndInvoke() Method को Parameter के रूप में IAsyncResult Compatible Type की जरूरत होती है।

वास्तव में BeginInvoke() Method से Return होने वाला IAsyncResult Compatible Type Object एक Coupling Mechanism है जो Calling Thread को जरूरत होने पर बाद में EndInvoke() Method के माध्‍यम से Asynchronous Method Invocation का Result प्राप्त करने की सुविधा देता है।

यानी BeginInvoke() Method के माध्‍यम से Invoking Method द्वारा जो Result Generate होता है, उसे IAsyncResult Object के रूप में Return किया जाता है और बाद में जरूरत होने पर इसी IAsyncResult Object को EndInvoke() Method में प्राप्त करने के लिए Parameter की तरह Pass कर दिया जाता है। System Namespace में इस IAsyncResult को निम्नानुसार तरीके से Define किया गया है:

	public interface IAsyncResult
	{
		object AsyncState { get; }
		WaitHandle AsyncWaitHandle { get; }
		bool CompletedSynchronously { get; }
		bool IsCompleted { get; }
	}

सामान्‍यत: हम इन Member Methods यानी BeginInvoke() EndInvoke() के Manual Invoking को Ignore कर सकते हैं। बस हमें केवल BeginInvoke() Method से Return होने वाले IAsyncResult Compatible Object को Cache करना होता है और उसे उस समय EndInvoke() में Parameter की तरह Pass करना होता है, जब हम Method Invocation के Result को प्राप्त करना चाहते हैं।

साथ ही जब हम Invoke किए जाने वाले Method से किसी मान को Return भी करवाना चाहते हैं, तब IAsyncResult Compatible Object Method द्वारा Return होने वाले मानों को Access करने के लिए हम IAsyncResult Interface की AsyncState, AsyncWaitHandle CompletedSynchronouslyIsCompleted Properties को भी हम अपनी जरूरत के अनुसार Implement कर सकते हैं।

जब हम किसी Method को Asynchronously Invoke करते हैं जो कि void Return करता है, तो उस समय हमें केवल Method को Invoke ही करना होता है और इस स्थिति में हमें IAsyncResult Compatible Object को Catch करना अथवा EndInvoke() को Use करना जरूरी नहीं होता क्योंकि उस स्थिति में Method द्वारा कोई मान Return नहीं हो रहा होताए जिसे Handle करने के लिए हमें IAsyncResult Interface की Properties को Implement करना पडे।

C# in Hindiये Article इस वेबसाईट पर Selling हेतु उपलब्‍ध EBook C#.NET in Hindi से लिया गया है। इसलिए यदि ये Article आपके लिए उपयोगी रहा, तो निश्चित रूप से ये पुस्तक भी आपके लिए काफी उपयोगी साबित होगी। 

C#.NET in Hindi | Page:908 | Format: PDF

BUY NOW GET DEMO REVIEWS