17

我有问题。我正在编写一个基准测试,并且我有一个功能可以在 2 秒内或约 5 分钟后完成(取决于输入数据)。如果它执行超过 3 秒,我想停止该功能......

我该怎么做?

非常感谢!

4

9 回答 9

61

嗯...,我有同样的问题,在阅读了这里的所有答案和参考的博客之后,我解决了这个问题,

它让我可以执行任何有时间限制的代码块,声明包装器方法

    public static bool ExecuteWithTimeLimit(TimeSpan timeSpan, Action codeBlock)
    {
        try
        {
            Task task = Task.Factory.StartNew(() => codeBlock());
            task.Wait(timeSpan);
            return task.IsCompleted;
        }
        catch (AggregateException ae)
        {
            throw ae.InnerExceptions[0];
        }   
    }

并用它来包装任何这样的代码块

    // code here

    bool Completed = ExecuteWithTimeLimit(TimeSpan.FromMilliseconds(1000), () =>
    {
         //
         // Write your time bounded code here
         // 
    });

    //More code
于 2012-05-11T02:17:52.113 回答
7

最好的方法是您的函数可以经常检查其执行时间以决定停止它需要太长时间。

如果不是这种情况,则在单独的线程中运行该函数。在您的主线程中启动一个 3 秒计时器。当计时器过去时,使用Thread.Abort() 终止单独的线程(当然,除非函数已经结束)。请参阅函数文档中的示例代码和使用说明。

于 2011-09-14T09:07:41.883 回答
4

C# 中停止函数的最佳方法是在函数中使用关键字,但是在持续至少 3 秒后,return我怎么知道何时使用关键字将函数中途停止?return来自的Stopwatch班级System.Diagnostics就是答案。这个持续 2 秒到 5 分钟(取决于输入数据)的复杂函数在逻辑上使用了许多循环,甚至可能使用递归,所以我给你的解决方案是,在该函数的第一行代码中,创建一个Stopwatch使用的实例System.Diagnostics使用new关键字,通过调用Start()Stopwatch 类的函数来启动它,并在每个循环和循环的开头,添加以下代码:

if (stopwatch.ElapsedMilliseconds >= 3000) { 
     stopwatch.Stop();
     // or 
     stopwatch.Reset(); 
     return;
 } 

(提示:您可以用手键入一次,按Ctrl+C复制,然后按Ctrl+V粘贴)。如果该函数使用递归,为了节省内存,请先创建 Stopwatch 全局实例而不是将其创建为本地实例,如果它在代码开头没有运行,则启动它。IsRunning您可以通过 Stopwatch 类知道这一点。然后询问经过的时间是否超过3秒,如果是(true)停止或重置秒表,并使用return关键字停止递归循环,很好的开始功能,如果你的功能持续很长时间主要是递归超过循环。这是。如您所见,它非常简单,我测试了这个解决方案,结果表明它有效!自己试试吧!

于 2013-03-04T18:56:08.677 回答
3

您可以使用 fork/join 模式,在任务并行库中,这是通过Task.WaitAll()实现的

using System.Threading.Tasks;

void CutoffAfterThreeSeconds() {

    // start function on seperate thread
    CancellationTokenSource cts = new CancellationTokenSource();
    Task loop = Task.Factory.StartNew(() => Loop(cts.Token));

    // wait for max 3 seconds
    if(Task.WaitAll(new Task[]{loop}, 3000)){
       // Loop finished withion 3 seconds
    } else {
       // it did not finish within 3 seconds
       cts.Cancel();           
    }        
}

// this one takes forever
void Loop() {
    while (!ct.IsCancellationRequested) {
        // your loop goes here
    }
    Console.WriteLine("Got Cancelled");
}

这将在单独的线程上启动另一个任务,然后等待 3000 毫秒以使其完成。如果它确实在超时内完成,则返回 true,否则返回 false,因此您可以使用它来决定下一步要做什么。

您可以使用CancellationToken与另一个线程进行通信,结果不再需要它,因此它可以优雅地停止。

问候格特扬

于 2011-09-14T09:17:49.030 回答
3
private static int LongRunningMethod()
{
    var r = new Random();

    var randomNumber = r.Next(1, 10);

    var delayInMilliseconds = randomNumber * 1000;

    Task.Delay(delayInMilliseconds).Wait();

    return randomNumber;
}

var task = Task.Run(() =>
{
    return LongRunningMethod();
});

bool isCompletedSuccessfully = task.Wait(TimeSpan.FromMilliseconds(3000));

if (isCompletedSuccessfully)
{
    return task.Result;
}
else
{
    throw new TimeoutException("The function has taken longer than the maximum time allowed.");
}

它对我有用!资料来源:https ://jeremylindsayni.wordpress.com/2016/05/28/how-to-set-a-maximum-time-to-allow-ac-function-to-run-for/

于 2019-03-21T11:00:26.427 回答
0

在线程中运行此函数并在 3 秒后将其终止检查此函数内的经过时间(我认为它在那里循环)。

于 2011-09-14T08:52:07.410 回答
0

由于 C# 和 .net 框架不是实时环境,因此您甚至无法保证 3 秒的计数。即使你接近那个,你仍然需要打电话给

if(timeSpan > TimeSpan.FromSeconds(3) then goto endindentifier;在方法中的所有其他调用之前。

所有这一切都是错误的,所以不,据我所知,没有可靠的方法可以做到这一点。

虽然你可以试试这个解决方案

https://web.archive.org/web/20140222210133/http://kossovsky.net/index.php/2009/07/csharp-how-to-limit-method-execution-time

但我只是不会在.net 应用程序中做这样的事情。

于 2011-09-14T08:52:20.523 回答
0

使用带有高性能计数器的操作系统回调,然后杀死你的线程(如果存在)

于 2011-09-14T09:03:12.353 回答
0

可以在单独的线程中执行函数并使用Thread.Join(millisecondsTimeout)限制其执行:

using System.Threading;

Thread workThread = new Thread(DoFunc);
workThread.Start(param);

if (!workThread.Join(3000))
{
    // DoFunc() took longer than 3 seconds. Thread was aborted
}

private void DoFunc(object param)
{
    // do some long work
}
于 2021-04-18T16:25:59.080 回答