如何为方法设置超时

发布于 2024-08-04 01:31:14 字数 23 浏览 2 评论 0原文

如何为繁忙的方法设置超时+C#。

how do set a timeout for a busy method +C#.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

玉环 2024-08-11 01:31:14

好吧,这就是真正的答案。

...

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# 的两个最有趣的部分。首先,要异步调用该方法,请使用具有花哨的 BeginInvoke 魔力的委托。

然后,使用监视器将消息从 LongRunningMethod 发送回 Im PatientMethod,让它知道它何时完成,或者是否在某个时间内没有收到消息。时间长了,就放弃吧。

(ps-只是开玩笑,这才是真正的答案。我知道有 2^9303 种剥猫皮的方法。尤其是在 .Net 中)

Ok, here's the real answer.

...

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.
  }
}

   ...

This combines two of the most fun parts of using C#. First off, to call the method asynchronously, use a delegate which has the fancy-pants BeginInvoke magic.

Then, use a monitor to send a message from the LongRunningMethod back to the ImpatientMethod to let it know when it's done, or if it hasn't heard from it in a certain amount of time, just give up on it.

(p.s.- Just kidding about this being the real answer. I know there are 2^9303 ways to skin a cat. Especially in .Net)

彡翼 2024-08-11 01:31:14

你不能这样做,除非你改变方法。

有两种方法:

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

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

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

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

第三种方法是打电话给某人,要求他们在家里寻找你借给他们的书,在你在电话那头等了 5 分钟后,你只需说“哦,扔掉它”,然后挂断电话。最终,另一个人会找到这本书并回到电话旁,却发现你不再关心结果。

You can not do that, unless you change the method.

There are two ways:

  1. The method is built in such a way that it itself measures how long it has been running, and then returns prematurely if it exceeds some threshold.
  2. The method is built in such a way that it monitors a variable/event that says "when this variable is set, please exit", and then you have another thread measure the time spent in the first method, and then set that variable when the time elapsed has exceeded some threshold.

The most obvious, but unfortunately wrong, answer you can get here is "Just run the method in a thread and use Thread.Abort when it has ran for too long".

The only correct way is for the method to cooperate in such a way that it will do a clean exit when it has been running too long.

There's also a third way, where you execute the method on a separate thread, but after waiting for it to finish, and it takes too long to do that, you simply say "I am not going to wait for it to finish, but just discard it". In this case, the method will still run, and eventually finish, but that other thread that was waiting for it will simply give up.

Think of the third way as calling someone and asking them to search their house for that book you lent them, and after you waiting on your end of the phone for 5 minutes you simply say "aw, chuck it", and hang up. Eventually that other person will find the book and get back to the phone, only to notice that you no longer care for the result.

帅气称霸 2024-08-11 01:31:14

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

这是示例代码:

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

This is an old question but it has a simpler solution now that was not available then: Tasks!

Here is a sample code:

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
悲歌长辞 2024-08-11 01:31:14

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

While MojoFilter's answer is nice it can lead to leaks if the "LongMethod" freezes. You should ABORT the operation if you're not interested in the result anymore.

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();
}
甜`诱少女 2024-08-11 01:31:14

您可以在单独的线程中运行该方法,并对其进行监视,如果运行时间过长则强制其退出。一个好方法(如果您可以这样称呼它)是为 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);

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

You can run the method in a separate thread, and monitor it and force it to exit if it works too long. A good way, if you can call it as such, would be to develop an attribute for the method in Post Sharp so the watching code isn't littering your application.

I've written the following as sample code(note the sample code part, it works, but could suffer issues from multithreading, or if the method in question captures the ThreadAbortException would break it):

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

With the following invocation:

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

I need to work on my code readability.

逆流 2024-08-11 01:31:14

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

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

Methods don't have timeouts in C#, unless your in the debugger or the OS believes your app has 'hung'. Even then processing still continues and as long as you don't kill the application a response is returned and the app continues to work.

Calls to databases can have timeouts.

甜味拾荒者 2024-08-11 01:31:14

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

Could you create an Asynchronous Method so that you can continue doing other stuff whilst the "busy" method completes?

怪我闹别瞎闹 2024-08-11 01:31:14

我经常编写必须跨平台同步时间关键任务的应用程序。如果你可以避免 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 了解何时进行的指南thread.abort 是合适的。以下是我实现的概念:

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

I regularly write apps where I have to synchronize time critical tasks across platforms. If you can avoid thread.abort you should. See http://blogs.msdn.com/b/ericlippert/archive/2010/02/22/should-i-specify-a-timeout.aspx and http://www.interact-sw.co.uk/iangblog/2004/11/12/cancellation for guidelines on when thread.abort is appropriate. Here are the concept I implement:

  • Selective execution: Only run if a reasonable chance of success exists (based on ability to meet timeout or likelihood of success result relative to other queued items). If you break code into segments and know roughly the expected time between task chunks, you can predict if you should skip any further processing. Total time can be measured by wrapping an object bin tasks with a recursive function for time calculation or by having a controller class that watches workers to know expected wait times.
  • Selective orphaning: Only wait for return if reasonable chance of success exists. Indexed tasks are run in a managed queue. Tasks that exceed their timeout or risk causing other timeouts are orphaned and a null record is returned in their stead. Longer running tasks can be wrapped in async calls. See example async call wrapper: http://www.vbusers.com/codecsharp/codeget.asp?ThreadID=67&PostID=1
  • Conditional selection: Similar to selective execution but based on group instead of individual task. If many of your tasks are interconnected such that one success or fail renders additional processing irrelevant, create a flag that is checked before execution begins and again before long running sub-tasks begin. This is especially useful when you are using parallel.for or other such queued concurrency tasks.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文