2009-09-11 16 views

回答

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#的兩個最有趣的部分。首先,要異步調用該方法,請使用具有花式魔術褲的代表。

然後,使用監視器將消息從LongRunningMethod發送回ImpatientMethod,以告知消息何時完成,或者是否在一定時間內未收到消息,請放棄。

(PS-只是開玩笑這是真正的答案。我知道有2^9303的方式皮膚貓,尤其是在.NET)

+0

這對我有用:) – 2013-09-11 10:55:37

+4

它確實有效,但!請注意! - 當執行流程返回時,「LongRunningMethod」仍然在後臺運行!這可能是泄漏。 – Alex 2013-09-29 21:34:01

+0

這是完全正確的。如果你想停止等待一個動作,而不是停止一個動作,這是很好的。 – MojoFilter 2013-10-03 19:48:15

7

你不能這樣做,除非你改變方法。

有兩種方式:

  1. 的方法是建立在其本身的尺寸了多長時間運行的時間,如果超過某個閾值,然後返回過早這種方式。
  2. 該方法的構建方式是監視一個變量/事件,該變量說明「何時設置此變量,請退出」,然後您有另一個線程測量第一個方法花費的時間,然後設置當經過的時間超過某個閾值時變量。

最明顯的,但不幸的是,你可以在這裏得到的答案是「只要在線程中運行該方法,並在運行時間過長時使用Thread.Abort」。

唯一正確的方法是讓方法合作,以便在運行時間過長時進行乾淨的退出。

還有第三種方法,您可以在單獨的線程上執行該方法,但在等待完成後需要很長時間,您只需說「我不會等待它完成,但只是丟棄它「。在這種情況下,該方法仍然會運行,並最終完成,但等待它的其他線程將簡單放棄。

想想第三種方式叫某人,並要求他們在他們的房子裏搜索你借給他們的那本書,等到電話結束5分鐘後,你只需說出「aw,chuck it」,然後掛斷。最終,其他人會找到這本書,然後回到電話上,只是注意到你不再關心結果。

0

方法在C#中沒有超時,除非您在調試器或操作系統中認爲您的應用程序已「掛起」。即使這樣,處理仍然繼續,只要你不殺死應用程序,就會返回響應,應用程序繼續工作。

對數據庫的調用可能會超時。

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

我需要在我的代碼可讀性上工作。

+0

您仍然需要編寫代碼添加到方法做一個乾淨的出口時,它要完成。 – 2009-09-11 12:49:00

+0

你的意思是像抓住ThreadAbort異常和清理資源/提供退出代碼?這真的取決於所討論的方法。 – 2009-09-11 13:06:20

+0

如果通過「超時」,他的意思是「我想關閉我的程序,不要等待方法完成」,那麼是的,可以使用Thread.Abort,但這是唯一的場景。 – 2009-09-11 13:44:01

0

您可以創建一個Asynchronous Method,以便您可以在「繁忙」方法完成時繼續執行其他任務嗎?

3

雖然MojoFilter's answer是很好,如果「它可能導致泄漏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(); 
} 
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。下面是我實現的概念:

  • 選擇性執行:只有當一個合理的成功機會存在(基於滿足超時或相對於其他排隊的項目成功結果的可能性的能力)上運行。如果將代碼分解爲段並大致瞭解任務塊之間的預期時間,則可以預測是否應該跳過任何進一步處理。總時間可以通過用時間計算遞歸函數包裝對象倉任務來測量,或者通過讓控制器類監視工作人員知道預期的等待時間來測量。
  • 選擇性孤兒:如果存在合理的成功機會,請等待回報。索引的任務在受管隊列中運行。超過其超時或導致其他超時風險的任務將被孤立,並返回空記錄。長時間運行的任務可以包裝在異步調用中。請參閱示例異步調用封裝器:http://www.vbusers.com/codecsharp/codeget.asp?ThreadID=67&PostID=1
  • 有條件選擇:類似於選擇性執行,但基於組而不是單個任務。如果許多任務互相連接,以至於一次成功或失敗都會導致其他處理無關緊要,請創建一個在開始執行前檢查的標誌,並在長時間運行的子任務開始前再次執行檢查。當你使用parallel.for或其他這樣的排隊併發任務時,這是特別有用的。
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