2011-09-14 122 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