如何为方法设置超时

时间:2009-09-11 12:37:07

标签: c# timeout methods

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

8 个答案:

答案 0 :(得分:12)

好的,这是真正的答案。

...

void LongRunningMethod(object monitorSync)
{
   //do stuff    
   lock (monitorSync) {
     Monitor.Pulse(monitorSync);
   }
}

void ImpatientMethod() {
  Action<object> 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魔法的委托。

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

(p.s.-开玩笑说这才是真正的答案。我知道有2 ^ 9303种皮肤猫的方法。尤其是.Net)

答案 1 :(得分:7)

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

有两种方法:

  1. 该方法的构建方式是它本身可以测量运行的时间,然后在超过某个阈值时提前返回。
  2. 该方法的构建方式是监视一个变量/事件,该变量/事件显示“当设置此变量时,请退出”,然后您有另一个线程测量在第一个方法中花费的时间,然后设置该方法当经过的时间超过某个阈值时变量。
  3. 最明显的,但不幸的是错误,你可以得到的答案是“只需在线程中运行该方法并在运行太长时间时使用Thread.Abort”。

    唯一正确的方法是让方法以这样一种方式进行合作:当它运行的时间过长时,它会进行干净的退出。

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

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

答案 2 :(得分:3)

虽然MojoFilter's answer很好,但如果&#34; LongMethod&#34;可能会导致泄漏。冻结。如果你对结果不感兴趣,你应该中止操作。

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();
}

答案 3 :(得分:3)

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

以下是示例代码:

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

答案 4 :(得分:2)

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

我已经将以下内容编写为示例代码(请注意示例代码部分,它可以工作,但可能会遇到多线程问题,或者如果有问题的方法捕获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);

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

答案 5 :(得分:0)

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

调用数据库可能会超时。

答案 6 :(得分:0)

你可以创建一个Asynchronous Method,以便在“忙碌”方法完成时继续做其他事情吗?

答案 7 :(得分:0)

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

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