2009-10-08 65 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

相关问题