如何为方法设置超时

如何为busy方法+ C#设置超时。

好的,这是真正的答案。

... void LongRunningMethod(object monitorSync) { //do stuff lock (monitorSync) { Monitor.Pulse(monitorSync); } } void ImpatientMethod() { Action longMethod = LongRunningMethod; object monitorSync = new object(); bool timedOut; lock (monitorSync) { longMethod.BeginInvoke(monitorSync, null, null); timedOut = !Monitor.Wait(monitorSync, TimeSpan.FromSeconds(30)); // waiting 30 secs } if (timedOut) { // it timed out. } } ... 

这结合了使用C#的两个最有趣的部分。 首先,要异步调用该方法,请使用具有fancy-pants BeginInvoke魔法的BeginInvoke

然后,使用监视器将LongRunningMethod的消息发送回ImpatientMethod ,让它知道它何时完成,或者如果它在一定时间内没有收到消息,就放弃它。

(ps-开玩笑说这才是真正的答案。我知道有2 ^ 9303种皮肤猫的方法。特别是在.Net)

除非您更改方法,否则不能这样做。

有两种方法:

  1. 该方法以这样一种方式构建,即它本身测量它运行了多长时间,然后如果超过某个阈值则提前返回。
  2. 该方法的构建方式是监视一个变量/事件,该变量/事件显示“当设置此变量时,请退出”,然后您有另一个线程测量在第一个方法中花费的时间,然后在该变量时设置该变量经过的时间已超过某个门槛。

你可以得到的最明显,但不幸错误的答案是“只需在线程中运行该方法,并在运行时间过长时使用Thread.Abort”。

唯一正确的方法是该方法以这样的方式进行协作,即当它运行太长时它将执行干净的退出。

还有第三种方法,你在一个单独的线程上执行该方法,但在等待它完成后,这需要很长时间才能完成,你只需说“我不会等待它完成,但只是丢弃它“。 在这种情况下,该方法仍将运行,并最终完成,但等待它的其他线程将放弃。

想想第三种方式是打电话给某人并要求他们在他们的房子里搜索你借给他们的那本书,然后等到你手机结束5分钟后,你只需说“哇,扔掉它”,然后挂断电话。 最终,其他人会找到这本书并重新打电话,只是注意到你不再关心结果。

虽然MojoFilter的答案很好,但如果“LongMethod”冻结,它可能导致泄漏。 如果您对结果不感兴趣,您应该中止操作。

 public void LongMethod() { //do stuff } public void ImpatientMethod() { Action longMethod = LongMethod; //use Func if you need a return value ManualResetEvent mre = new ManualResetEvent(false); Thread actionThread = new Thread(new ThreadStart(() => { var iar = longMethod.BeginInvoke(null, null); longMethod.EndInvoke(iar); //always call endinvoke mre.Set(); })); actionThread.Start(); mre.WaitOne(30000); // waiting 30 secs (or less) if (actionThread.IsAlive) actionThread.Abort(); } 

这是一个老问题,但它现在有一个更简单的解决方案,然后就没有了:任务!

这是一个示例代码:

 var task = Task.Run(() => LongRunningMethod());//you can pass parameters to the method as well if (task.Wait(TimeSpan.FromSeconds(30))) return task.Result; //the method returns elegantly else throw new TimeoutException();//the method timed-out 

您可以在单独的线程中运行该方法,并监视它并在其工作时间过长时强制退出。 一个好方法,如果你可以这样称呼它,就是在Post Sharp中为方法开发一个属性,这样看守代码就不会乱丢你的应用程序。

我已经将以下内容编写为示例代码(请注意示例代码部分,它可以工作,但可能会遇到multithreading问题,或者如果有问题的方法捕获ThreadAbortException会破坏它):

 static void ActualMethodWrapper(Action method, Action callBackMethod) { try { method.Invoke(); } catch (ThreadAbortException) { Console.WriteLine("Method aborted early"); } finally { callBackMethod.Invoke(); } } static void CallTimedOutMethod(Action method, Action callBackMethod, int milliseconds) { new Thread(new ThreadStart(() => { Thread actionThread = new Thread(new ThreadStart(() => { ActualMethodWrapper(method, callBackMethod); })); actionThread.Start(); Thread.Sleep(milliseconds); if (actionThread.IsAlive) actionThread.Abort(); })).Start(); } 

通过以下调用:

 CallTimedOutMethod(() => { Console.WriteLine("In method"); Thread.Sleep(2000); Console.WriteLine("Method done"); }, () => { Console.WriteLine("In CallBackMethod"); }, 1000); 

我需要处理我的代码可读性。

除非您在调试器或操作系统中认为您的应用已“挂起”,否则方法在C#中没有超时。 即使这样,处理仍然继续,只要您不杀死应用程序,就会返回响应并且应用程序继续工作。

对数据库的调用可能会超时。

您可以创建一个异步方法,以便在“忙”方法完成时继续执行其他操作吗?

我经常编写应用程序,我必须跨平台同步时间关键任务。 如果你可以避免thread.abort你应该。 请参阅http://blogs.msdn.com/b/ericlippert/archive/2010/02/22/should-i-specify-a-timeout.aspx和http://www.interact-sw.co.uk/iangblog / 2004/11/12 /取消有关何时适合使用thread.abort的指南。 以下是我实施的概念:

  • 选择性执行:仅在存在合理成功机会的情况下运行(基于满足超时的能力或相对于其他排队项目的成功可能性)。 如果将代码分成多个段并大致了解任务块之间的预期时间,则可以预测是否应该跳过任何进一步的处理。 总时间可以通过使用递归函数包装对象bin任务来计算时间,或者通过使控制器类监视工作人员知道预期的等待时间来测量。
  • 选择性孤儿:只有在存在合理的成功机会时才等待返回。 索引任务在托管队列中运行。 超出其超时或导致其他超时的风险的任务将被孤立,并且将返回空记录。 较长时间运行的任务可以包含在异步调用中。 请参阅示例异步调用包装器: http ://www.vbusers.com/codecsharp/codeget.asp?ThreadID = 67&PostID = 1
  • 条件选择:与选择性执行类似,但基于组而不是单个任务。 如果您的许多任务相互连接,一次成功或失败会导致其他处理无关紧要,请创建一个在执行开始之前检查的标志,并在长时间运行子任务之前再次检查。 当您使用parallel.for或其他此类排队并发任务时,这尤其有用。