2009-11-11 25 views
10

デリゲートがメソッドが起動する前にEndInvokeを呼び出す必要があるのはなぜですか? EndInvoke(スレッドをブロックする)を呼び出す必要がある場合、実際には非同期呼び出しではありませんか?非同期デリゲートメソッドでEndInvokeを呼び出す必要があるのはなぜですか?

ここに実行しようとしているコードです。

class Program 
    { 
     private delegate void GenerateXmlDelegate(); 

     static void Main(string[] args) 
     { 
      GenerateXmlDelegate worker = new GenerateXmlDelegate(GenerateMainXml); 
      IAsyncResult result = worker.BeginInvoke(null, null); 
     } 

     private static void GenerateMainXml() 
     { 
      Thread.Sleep(10000); 
      Console.WriteLine("GenerateMainXml Called by delegate"); 
     } 
    } 

答えて

15

EndInvokeに電話する必要がある理由は、メモリリークを避けるためです。 .NetはEndInvokeに電話するまで、関数の結果(または例外)に関する情報を格納します。

に指定した完了ハンドラでEndInvokeと呼び出し、非同期性を保持することができます。

EDIT

例えば:

class Program { 
    private delegate void GenerateXmlDelegate(); 

    static void Main(string[] args) { 
     GenerateXmlDelegate worker = new GenerateXmlDelegate(GenerateMainXml); 
     IAsyncResult result = worker.BeginInvoke(delegate { 
      try { 
       worker.EndInvoke(); 
      } catch(...) { ... } 
     }, null); 
    } 

    private static void GenerateMainXml() { 
     Thread.Sleep(10000); 
     Console.WriteLine("GenerateMainXml Called by delegate"); 
    } 
} 

あなたは非同期呼び出しを発射し、それを忘れたい場合、あなたはこのように、ThreadPoolを使用することができます。

ThreadPool.QueueUserWorkItem(delegate { GenerateMainXml(); }); 
+0

私の例を拡張して、Completion Handlerの意味を実証することはできますか?私が読んだすべての記事から、BeginInvokeを呼び出すだけでメソッド呼び出しが呼び出されることが示唆されています。 –

+1

これはちょうど正しいです - メモリリークは発生しません。 https://gist.github.com/jcdickinson/9109599。しかし、ある種のシナリオでは、 'Begin/End-Invoke'ペアで追跡するものがあります。例えば、' Socket'オペレーションで 'End *'を呼び出さなければ、あなたのソケットパフォーマンスカウンターは完全に駄目になりますメモリリークがない場合、値はまったく間違っています)。 –

6

SLAKsによると、EndInvokeはメモリリークを保証します。

BeginInvokeはまだ非同期です。次のコードを考えてみます。このコードはBeginInvoke/EndInvoke呼び出しなしで書かれていた場合

static void Main() { 
    Func<double> slowCalculator = new Func<double>(PerformSlowCalculation); 
    IAsyncResult slowCalculation = slowCalculator.BeginInvoke(null, null); 

    // lots of stuff to do while slowCalculator is doing its thing 

    Console.WriteLine("Result is {0}", slowCalculator.EndInvoke(slowCalculation)); 
} 

static double PerformSlowCalculation() { 
    double result; 

    // lots and lots of code 

    return result; 
} 

を、PerformSlowCalculationMainはその「ものがたくさん」の残りの部分を行うことができます前に完了しなければなりません。このように、2つは同時に起こることができます。

GenerateXmlDelegateを使用している例では、何も返さないのに、まだEndInvokeが必要です。これを行う方法は次のとおりです。

static void Main(string[] args) { 
    GenerateXmlDelegate worker = new GenerateXmlDelegate(GenerateMainXml); 
    IAsyncResult result = worker.BeginInvoke(GenerateXmlComplete, null); 
} 

private static void GenerateXmlComplete(IAsyncResult result) { 
    AsyncResult realResult = result as AsyncResult; 
    GenerateXmlDelegate worker = result.AsyncDelegate as GenerateXmlDelegate; 
    worker.EndInvoke(); 
} 
関連する問題