在工作中,遇到这样一个需求,我要做一个业务,要验证一下现有的数据是否正确,但这个验证又不是必须的,只是说如果这里验证不通过,后面流程就可以不走了,但是如果这里没有验证到,后面也会有验证。也就是说不影响主流程,算得上是一个优化吧。比如我要查询一个东西,但是这个时间不能超过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)、总结
从上面的结果可以看出:
第一、有两个线程
第二、如果方法超时,则不会将被调用的方法执行完毕,可以看出,方法是执行了,但由于超时,结果是不对的。如果方法没有超时,结果为正确的。这与上面方法的区别在于,方法超时就不会继续执行了。