2009-10-08 55 views
0

我正在學習線程。我的意圖是將一些值傳遞給一個計算方法,如果結果將不會在20毫秒內返回,我會報告「操作超時」。基於我的內容,我已經實現了代碼如下:如何在異步調用中報告超時?

public delegate long CalcHandler(int a, int b, int c); 


public static void ReportTimeout() 
    { 
     CalcHandler doCalculation = Calculate; 

     IAsyncResult asyncResult = 
     doCalculation.BeginInvoke(10,20,30, null, null); 

     if (!asyncResult.AsyncWaitHandle.WaitOne(20, false)) 
     { 
      Console.WriteLine("..Operation Timeout..."); 
     } 

     else 
     { 
     // Obtain the completion data for the asynchronous method. 
     long val; 
     try 
     { 
      val= doCalculation.EndInvoke(asyncResult); 
      Console.WriteLine("Calculated Value={0}", val); 
     } 
     catch 
     { 
      // Catch the exception 
     } 
    } 

    } 

public static long Calculate(int a,int b,int c) 
    { 
     int m; 
     //for testing timeout,sleep is introduced here. 
     Thread.Sleep(200); 
     m = a * b * c; 
     return m; 
    } 

問題:

(1)是否有報告超時的正確方法? (2)如果時間到了,我不會調用EndInvoke()。在這種情況下調用EndInvoke()是強制性的嗎?

(3)我聽說

「即使你不想處理您的異步方法的返回值,你應該調用EndInvoke;否則,你可能每次啓動時泄漏內存使用BeginInvoke進行異步調用「

與內存相關的風險是什麼?你能舉個例子嗎?

回答

2

答案

(1)通常你只是把System.TimeoutException

(2)是必需的EndInvoke()的原因是,如果返回值(或拋出異常)具有內存分配的GC可能無法快速清理它。我還沒有看到這是一個大問題......但那只是我。

如果你真的擔心它,你可以調用ThreadPool.QueueUserWorkItem這是主要是上面的異步調用將做什麼。 (注意:可能是WinForms或其他線程相關上下文中的問題)。無論如何,你可以運行你自己的工作項目如下:

public static long Calc(CalcHandler fn, int a, int b, int c) 
    { 
     return Run<long>(TimeSpan.FromSeconds(20), delegate { return fn(a, b, c); }); 
    } 

    public static T Run<T>(TimeSpan timeout, Func<T> operation) 
    { 
     Exception error = null; 
     T result = default(T); 

     ManualResetEvent mre = new ManualResetEvent(false); 
     System.Threading.ThreadPool.QueueUserWorkItem(
      delegate(object ignore) 
      { 
       try { result = operation(); } 
       catch (Exception e) { error = e; } 
       finally { mre.Set(); } 
      } 
     ); 
     if (!mre.WaitOne(timeout, true)) 
      throw new TimeoutException(); 
     if (error != null) 
      throw new TargetInvocationException(error); 
     return result; 
    } 
1

從超時值,是的,這是要設置超時如您所料。

至於內存風險。如果您沒有調用EndInvoke,仍然存在對代理的引用,並且在應用程序退出之前所使用的資源可能不會被垃圾收集,則存在風險。確切的實施並非100%記錄在我發現的內容中,但可以通過類似ANTS Profiler的工具進行確認。

這是一個有幫助的discussion

相關問題