首页 > 代码库 > 设置调用方法的超时时间

设置调用方法的超时时间

<style></style>

  在工作中,遇到这样一个需求,我要做一个业务,要验证一下现有的数据是否正确,但这个验证又不是必须的,只是说如果这里验证不通过,后面流程就可以不走了,但是如果这里没有验证到,后面也会有验证。也就是说不影响主流程,算得上是一个优化吧。比如我要查询一个东西,但是这个时间不能超过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:Main10 end11 5:ThreadName:subThread12 6:ThreadName:subThread13 7:ThreadName:subThread14 8:ThreadName:subThread15 9:ThreadName:subThread16 sum = 4517 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 end10 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:Main10 ThreadName:Main, 结果是:011 end

  b、不超时的情况(将上面测试需要修改的代码修改为:int result = CallWithTimeOutFun(ComputeSumResult, 3, 3000);// 测试需要修改的代码)

1 start2 0,ThreadName:threadToKill3 1,ThreadName:threadToKill4 2,ThreadName:threadToKill5 ThreadName:Main6 没有超时7 ThreadName:Main8 ThreadName:Main, 结果是:39 end

  (4)、总结

  从上面的结果可以看出:

    第一、有两个线程

    第二、如果方法超时,则不会将被调用的方法执行完毕,可以看出,方法是执行了,但由于超时,结果是不对的。如果方法没有超时,结果为正确的。这与上面方法的区别在于,方法超时就不会继续执行了。

设置调用方法的超时时间