在工作中,遇到這樣一個需求,我要做一個業務,要驗證一下現有的數據是否正確,但這個驗證又不是必須的,只是說如果這里驗證不通過,后面流程就可以不走了,但是如果這里沒有驗證到,后面也會有驗證。也就是說不影響主流程,算得上是一個優化吧。比如我要查詢一個東西,但是這個時間不能超過1秒。
在網上查了一下,基本上都是異步執行,有兩個線程來做。我查到有兩種方法。
第一種 獨立成一個類
代碼如下:
(1)、FuncTimeOut類
/// <summary> /// 超時設置類 /// </summary> public class FuncTimeOut { /// <summary> /// 信號量 /// </summary> private ManualResetEvent manu = new ManualResetEvent(false); /// <summary> /// 是否接受到信號 /// </summary> private bool isgetSignal; /// <summary> /// 設置超時時間 /// </summary> private int timeout; /// <summary> /// 要委托調用的方法的一個委托 /// </summary> private Action<int> funcNeedRun; /// <summary> /// 構造函數 /// </summary> /// <param name="action">委托</param> /// <param name="timeout">超時時間</param> public FuncTimeOut(Action<int> action, int timeout) { this.funcNeedRun = action; this.timeout = timeout; } /// <summary> /// 執行方法 /// </summary> /// <param name="param">參數</param> public void Execute(int param) { Action<int> tempAction = this.CombineActionAndManuset; var r = tempAction.BeginInvoke(param, this.MyAsynCallback, null); this.isgetSignal = this.manu.WaitOne(this.timeout); if (this.isgetSignal == true) { Console.WriteLine("未超時."); Console.WriteLine("ThreadName:" + Thread.CurrentThread.Name); } else { Console.WriteLine("超時"); Console.WriteLine("ThreadName:" + Thread.CurrentThread.Name); } } /// <summary> /// 回調函數 /// </summary> /// <param name="ar">異步操作時的狀態</param> private void MyAsynCallback(IAsyncResult ar) { if (this.isgetSignal == false) { Console.WriteLine(Thread.CurrentThread.Name + ",超時,放棄執行回調函數"); Thread.CurrentThread.Abort(); } else { Console.WriteLine(Thread.CurrentThread.Name + ",執行成功"); } } /// <summary> /// 執行方法 /// </summary> /// <param name="para">參數</param> private void CombineActionAndManuset(int para) { Thread.CurrentThread.Name = "subThread"; this.funcNeedRun(para); this.manu.Set(); } }
(2)、測試代碼
/// <summary> /// Class Program /// </summary> public class Program { /// <summary> /// Defines the entry point of the application. /// </summary> /// <param name="args">The args.</param> public static void Main(string[] args) { TestFuncTimeOut(); Console.Read(); } #region FunTimeOut測試 /// <summary> /// 測試超時設置操作 /// </summary> private static void TestFuncTimeOut() { Console.WriteLine("start"); Thread.CurrentThread.Name = "Main"; FuncTimeOut ft = new FuncTimeOut(ComputeSum, 3000); ft.Execute(10); // 測試修改點 Console.WriteLine("ThreadName:" + Thread.CurrentThread.Name); Console.WriteLine("end"); } /// <summary> /// Does the STH. /// </summary> /// <param name="num">The num.</param> private static void ComputeSum(int num) { int sum = 0; for (int i = 0; i < num; i++) { Thread.Sleep(500); sum += i; Console.WriteLine(i + ":ThreadName:" + Thread.CurrentThread.Name); } Console.WriteLine("sum = " + sum); // return sum; } #endregion }
(3)、執行結果
a、超時的情況(上面的測試代碼測出來的結果)
1 start 2 0:ThreadName:subThread 3 1:ThreadName:subThread 4 2:ThreadName:subThread 5 3:ThreadName:subThread 6 4:ThreadName:subThread 7 超時 8 ThreadName:Main 9 ThreadName:Main 10 end 11 5:ThreadName:subThread 12 6:ThreadName:subThread 13 7:ThreadName:subThread 14 8:ThreadName:subThread 15 9:ThreadName:subThread 16 sum = 45 17 subThread,超時,放棄執行回調函數
b、未超時的情況(將上述黃色部分的標示改為:ft.Execute(3);的結果)
1 start 2 0:ThreadName:subThread 3 1:ThreadName:subThread 4 2:ThreadName:subThread 5 sum = 3 6 未超時. 7 ThreadName:Main 8 ThreadName:Main 9 end 10 subThread,執行成功
(4)、總結
從上面的結果可以看出:
第一、有兩個線程
第二、無論是否超時,方法都會被執行完畢,如果超時,則不忘下執行回調函數,否則執行。
第二種 封裝成一個方法
(1)、源代碼
/// <summary> /// 連續整數求和【測試方法】 /// </summary> /// <param name="num">個數</param> /// <returns>結果</returns> private static int ComputeSumResult(int num) { int sum = 0; for (int i = 0; i < num; i++) { Thread.Sleep(500); sum += i; Console.WriteLine(i + ",ThreadName:" + Thread.CurrentThread.Name); } return sum; } /// <summary> /// 超時方法調用 /// </summary> /// <param name="func">要調用的方法</param> /// <param name="param">要調用方法的參數</param> /// <param name="timeoutMillisecondes">超時時間</param> /// <returns>結束</returns> private static int CallWithTimeOutFun(Func<int, int> func, int param, int timeoutMillisecondes) { Thread threadToKill = null; int sum = 0; Action wrappedAction = () => { threadToKill = Thread.CurrentThread; threadToKill.Name = "threadToKill"; sum = func(param); }; IAsyncResult result = wrappedAction.BeginInvoke(null, null); if (result.AsyncWaitHandle.WaitOne(timeoutMillisecondes)) { Console.WriteLine("ThreadName:" + Thread.CurrentThread.Name); wrappedAction.EndInvoke(result); Console.WriteLine("沒有超時"); Console.WriteLine("ThreadName:" + Thread.CurrentThread.Name); return sum; } else { Console.WriteLine("ThreadName:" + Thread.CurrentThread.Name); threadToKill.Abort(); Console.WriteLine("超時"); Console.WriteLine("ThreadName:" + Thread.CurrentThread.Name); return sum; } }
(2)、測試代碼
/// <summary> /// Class Program /// </summary> public class Program { /// <summary> /// Defines the entry point of the application. /// </summary> /// <param name="args">The args.</param> public static void Main(string[] args) { Console.WriteLine("start"); Thread.CurrentThread.Name = "Main"; int result = CallWithTimeOutFun(ComputeSumResult, 10, 3000);// 測試需要修改的代碼 Console.WriteLine("ThreadName:" + Thread.CurrentThread.Name + ", 結果是:" + result); Console.WriteLine("end"); Console.Read(); } }
(3)、測試結果
a、超時情況
1 start 2 0,ThreadName:threadToKill 3 1,ThreadName:threadToKill 4 2,ThreadName:threadToKill 5 3,ThreadName:threadToKill 6 4,ThreadName:threadToKill 7 ThreadName:Main 8 超時 9 ThreadName:Main 10 ThreadName:Main, 結果是:0 11 end
b、不超時的情況(將上面測試需要修改的代碼修改為:int result = CallWithTimeOutFun(ComputeSumResult, 3, 3000);// 測試需要修改的代碼)
1 start 2 0,ThreadName:threadToKill 3 1,ThreadName:threadToKill 4 2,ThreadName:threadToKill 5 ThreadName:Main 6 沒有超時 7 ThreadName:Main 8 ThreadName:Main, 結果是:3 9 end
(4)、總結
從上面的結果可以看出:
第一、有兩個線程
第二、如果方法超時,則不會將被調用的方法執行完畢,可以看出,方法是執行了,但由於超時,結果是不對的。如果方法沒有超時,結果為正確的。這與上面方法的區別在於,方法超時就不會繼續執行了。