2011-09-14 81 views
9

我遇到了问题。我正在编写一个基准测试,我有一个功能比在2秒内或5分钟后(取决于输入数据)完成。如果执行时间超过3秒,我想停止该功能...如何在c sharp中限制函数的执行时间?

我该怎么做?

非常感谢!

+0

可能是重复http://stackoverflow.com/questions/5025509/how-to-estimate-method-execution-time – Reniuz

+0

是的,它是重复的,基准测试的结束方式与任何其他线程停止相同。 –

回答

3

最好的办法是你的函数可以检查其执行时间往往足以决定停止时间太长。

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

+0

确实很容易。如果你真的需要以不友好的方式杀死线程,使用线程是我知道的唯一方式。 – gjvdkamp

+0

是的,这似乎是最简单和最直接的方法。谢谢 – Novellizator

0

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

+1

这只会将函数变成一个检查循环,而没有其他功能。杀死线程也无法保证。无论如何,它不会被杀死,直到它退出该功能。 –

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应用程序中做这样的事情。

+0

嗨,最大。微软的Windows也不是一个实时的操作系统 –

+0

你可以在Windows上使用Win32和Interop使用回调函数,然后使用 –

+0

@Artur,我之所以说.net和不是Windows,是因为C#也可以在通过Mono的基于Unix的操作系统,我不确定是否所有支持Mono的操作系统都不是实时的。组装一个实时系统是可能的,但Mono最可能永远不会是实时的,而且.Net,因为目前没有必要。 –

0

使用的OS回调与喜性能计数器,然后杀了你的线程,如果存在

+0

杀死托管线程的API方式是否确保即时(在下一次处理器迭代中)线程终止? –

3

您可以用叉子/加盟模式,在任务并行库,这是与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与另一个线程进行通信,以使其不再需要,从而可以正常停止。

Regards Gert-Jan

+0

好吧,它似乎很容易和可用:)最后一个问题:我怎样才能以某种方式取消正在运行的循环()? – Novellizator

+0

这种依赖你在那里做什么......是某种循环(你可以在其中取消取消标记?)还是你调用其他一些你不能改变的代码?这决定了策略。如果long runnnig操作是你的代码,那么你使用CancellationToken。如果它是一些其他代码,那么你可能需要不那么友好,并真正杀死线程。这可能会导致不一致的状态。我将用取消令牌更新示例。 – gjvdkamp

+0

确定更新示例 – gjvdkamp

44

那么......,我有同样的问题,在这里阅读所有的答案和参照对象的博客后,我选定了这一点,

它让我执行任何代码块有时间限制,申报的包装方法

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 
+4

根据我的理解,如果它仍然在timeSpan之后运行,则不会停止操作codeBlock。在您的基准测试场景中,如果您有多个并行运行的代码,应该会大大改变您的结果。 –

+0

我想你需要写'Task task = new Task(codeBlock); task.Wait(时间跨度); task.Start();返回task.IsCompleted;'因为在你的代码中,你正在启动该方法并告诉它等待x次。但实际上只是分配任务等待并启动任务是一种更好的方法。 –

2

在C#中的最佳方式在中途停止功能是在功能上return关键字,但我怎么知道什么时候使用return关键字在中间停止功能,持续至少3秒后? System.DiagnosticsStopwatch类是答案。这个复杂的函数持续2秒到5分钟(取决于输入数据)在逻辑上使用很多循环,甚至可能是递归,所以我的解决方案是,在该函数的第一行代码中创建一个Stopwatch的实例使用System.Diagnosticsnew关键字,通过调用秒表类的Start()功能启动,并在每个循环和循环,一开始,添加以下代码:

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

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

+0

最好的答案是简单而快速的。你有很好的内容,但你应该考虑修改。 – WolfLink